[英]Java immutable-class rules
以下类是不可变的:
final class MyClass {
private final int[] array;
public MyClass(int[] array){
this.array = array;
}
}
不,不是因为数组的元素仍然可以更改。
int[] v1 = new int[10];
MyClass v2 = new MyClass(v1);
v1[0] = 42; // mutation visible to MyClass1
关于不变性规则的两分钱(我从阅读有效Java中保留了这一规定 - 一本好书!):
“不变性”是程序员和他自己之间的惯例。 编译器可能或多或少地强制执行该约定。
如果类的实例在应用程序代码执行的正常过程中没有更改,则它们是“不可变的”。 在某些情况下,我们知道它们不会改变,因为代码实际上禁止它; 在其他情况下,这只是我们如何使用该类的一部分。 例如,一个java.util.Date
实例是正式可变的(它上面有一个setTime()
方法),但习惯上它就好像它是不可变的一样处理它; 这只是一个应用程序范围的约定,不应该调用Date.setTime()
方法。
作为补充说明:
String
被记录为不可变的(这就是Javadoc所说的)。 但是如果你看一下源代码,你会发现一个String
实例包含一个名为hash
的私有字段,它可能会随着时间的推移而改变:这是hashCode()
返回的值的缓存。 我们仍然说String
是不可变的,因为hash
字段是一个内部优化,它没有从外部可见的效果。 final
的实例)。 并不是说这是一个好主意:它可能会破坏使用所述实例的其他代码段所使用的假设。 正如我所说,不变性是一个惯例:如果程序员想要自己打,那么他可以,但这会对生产力产生不利的副作用...... MyClass
实例的不变性? 这个问题没有通用的答案。 没有办法使数组不可变。 也就是说,没有办法阻止任何客户端代码设置或删除或添加项目到数组。
这是一个真正不可改变的选择:
private static class MyClass
{
private List<Integer> list;
private MyClass(final int[] array)
{
final List<Integer> tmplist = new ArrayList<Integer>(array.length);
for (int i : array)
{
tmplist.add(array[i]);
}
this.list = Collections.unmodifiableList(tmplist);
}
}
要使类不可变,您需要确保其上的所有字段都是final,并且这些字段的类型也是不可变的。
记住这可能是一种痛苦,但有一种工具可以帮助你。
Pure4J提供了一个注释@ImmutableValue
,您可以将其添加到接口或类中。
有一个maven插件可以在编译时检查您是否符合此后的不变性规则。
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.