不可变类?
2022-08-31 11:22:38
如何使Java类不可变,不可变性的必要性是什么,使用它有什么好处吗?
什么是不可变对象?
不可变对象是在实例化后不会更改状态的对象。
如何使对象不可变?
通常,可以通过定义一个没有公开其任何成员并且没有任何 setter 的类来创建不可变对象。
以下类将创建一个不可变对象:
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
从上面的示例中可以看出,只能在实例化对象时设置 的值,并且通过仅具有 getter () 对象的状态,在实例化后无法更改。ImmutableInt
getValue
但是,必须注意对象引用的所有对象也必须是不可变的,否则可以更改对象的状态。
例如,允许对数组的引用或通过 getter 获取,将允许通过更改数组或集合来更改内部状态:ArrayList
class NotQuiteImmutableList<T> {
private final List<T> list;
public NotQuiteImmutableList(List<T> list) {
// creates a new ArrayList and keeps a reference to it.
this.list = new ArrayList(list);
}
public List<T> getList() {
return list;
}
}
上述代码的问题在于,可以通过获取和操作,导致对象本身的状态被改变,因此,不是不可变的。ArrayList
getList
// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));
// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");
解决此问题的一种方法是在从 getter 调用时返回数组或集合的副本:
public List<T> getList() {
// return a copy of the list so the internal state cannot be altered
return new ArrayList(list);
}
不可变性的优势是什么?
不可变性的优势在于并发性。很难保持可变对象的正确性,因为多个线程可能试图更改同一对象的状态,导致某些线程看到同一对象的不同状态,具体取决于对所述对象的读取和写入的时间。
通过拥有不可变对象,可以确保所有查看该对象的线程都将看到相同的状态,因为不可变对象的状态不会改变。
除了已经给出的答案之外,我建议阅读《有效Java》第2版中的不可变性,因为有一些细节很容易被遗漏(例如防御性副本)。另外,Effective Java 2nd Ed. 是每个 Java 开发人员的必读书目。