我阅读了关于不可变对象的this question,并留下了关于不可变对象和最终字段的问题:
为什么我们需要不可变类中的实例变量为final?
例如,考虑这个不可变类:
public final class Immutable
{
private final int someVal;
public Immutable(int someVal)
{
this.someVal= someVal;
}
public int getVal() {
return val;
}
}
如果在上面的代码中没有set方法,并且实例变量只在构造函数中设置,为什么要求将实例变量声明为final?
答案 0 :(得分:5)
没有要求这样做变量final
。但是,如果您明确打算永远不要更改变量,那么将其设为final
通常是一种好习惯,因为这不仅会强制执行打字错误或其他错误的不变量,而且还会声明它的意图不可变,例如,其他程序员或你自己。
如果变量为public
,那么您需要将其设为final
,以确保接口代码无法更改其值。
请注意,您链接的问题并不直接相关,因为它讨论的是final
而不是变量的类。创建类final
意味着它不能继承,而不是它是不可变的。然而,在制作不可变对象时,肯定有一个案例需要注意该问题的内容及其答案;但它仍然是一个单独的问题。
答案 1 :(得分:4)
通过标记所有课程'字段final
,您明确表示您希望您的课程不可变。
假设您有以下课程:
public class Immutable {
private int value;
public Immutable (int value) {
this.value = value;
}
public int getValue () {
return value;
}
}
没有setter方法,因此可以很容易地假设这个类是不可变的。现在是哪个。但最终你的类会被其他程序员修改,这个程序员可能会为你的类添加一些方法:
public class Immutable {
private int value;
public Immutable (int value) {
this.value = value;
}
public int getValue () {
return value;
}
public void doSomething () {
value++;
}
}
如果字段不是final
,则无意中添加一个修改对象状态的方法非常容易。通过标记它们final
,这个其他程序员在尝试修改字段时会收到编译错误,并且必须问自己为什么这个字段final
,并且他的修改是否违反了这个字段的合同类。
有人可能会说Javadoc应该被用来记录所说的类是不可变的,但坦率地说,不是每个人都读Javadoc。在我看来,让代码说话本身更好。
答案 2 :(得分:1)
在不可变类中,您无法更改其属性/字段的状态。通常,它是通过不向类的客户端代码提供setter方法来完成的。
static final
关键字的组合用于使变量保持不变。声明为final的变量在初始化后永远不会改变它的值。
因为在不可变类中你永远不需要改变属性/字段状态,所以最好让它成为最终的。
答案 3 :(得分:1)
以前的答案是错误的。
要成为不可变对象,必须将所有属性声明为final
。
在某些线程之间存在数据争用的情况下,Java内存模型可以确保为final字段提供一定的保证,以防止它们返回不正确的默认值。
请参见https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5-110中的示例17.5-2。