具有 ArrayList 成员变量的不可变对象 - 为什么可以更改此变量?

我有一个具有各种成员变量的类。有一个构造函数,有 getter 方法,但没有 setter-method。实际上,此对象应该是不可变的。

public class Example {
   private ArrayList<String> list; 
}

现在我注意到以下内容:当我使用getter方法获得变量列表时,我可以添加新值等等 - 我可以更改.当我下次调用此变量时,将返回更改的变量。这怎么可能?我没有再设置它,我只是在它上面工作!这种行为是不可能的。那么这里有什么区别呢?ArrayListget()ArrayListString


答案 1

仅仅因为对列表的引用是不可变的,并不意味着它所引用的列表是不可变的。

即使做了,这也是允许的listfinal

// changing the object which list refers to
example.getList().add("stuff");

但这不允许

// changing list
example.list = new ArrayList<String>();   // assuming list is public

为了使列表不可变(也防止第一行),我建议您使用 Collections.unmodifiableList

public class Example {
    final private ArrayList<String> list;

    Example(ArrayList<String> listArg) {
        list = Collections.unmodifiableList(listArg);
    }
}

(请注意,这将创建列表的不可修改视图。如果有人保留了原始引用,则仍可以通过该引用修改列表。


对于字符串,此行为是不可能的。那么这里有什么区别呢?

这是因为 a 已经是不可变的(不可修改的),就像列表一样,如果你把它变成一个不可修改的列表。String

比较:

              String data structure  | List data structure
           .-------------------------+------------------------------------.
Immutable  | String                  | Collection.unmodifiableList(...)   |
-----------+-------------------------+------------------------------------|
Mutable    | StringBuffer            | ArrayList                          |
           '-------------------------+------------------------------------'

答案 2

您正在返回对 的引用。而且不是一成不变的。listlist


如果您不希望更改列表,请返回其副本:

public List<String> get() {
    return new ArrayList<String>(this.list);
}

或者,您可以返回一个不可修改的列表

public List<String> get() {
    return Collections.unmodifiableList(this.list);
}