为什么实例变量是最终的?
Why instance variable to be final?
我阅读了 this question 有关不可变对象的内容,并留下了有关不可变对象和最终字段的问题:
为什么我们需要不可变 class 中的实例变量是最终的?
例如,考虑这个不可变的 class:
public final class Immutable
{
private final int someVal;
public Immutable(int someVal)
{
this.someVal= someVal;
}
public int getVal() {
return val;
}
}
如果上述代码中没有set方法,实例变量只在构造函数中设置,为什么要求实例变量声明为final?
在不可变 class 中,您无法更改其 property/field 的状态。通常它是通过不向 class 的客户端代码提供 setter 方法来完成的。
和static final
关键字的组合用于使变量常量。声明为 final 的变量一旦被初始化就永远不能改变它的值。
因为在不可变的 class 中你永远不需要改变 property/field 状态,所以最好让它成为最终状态。
没有要求 使变量final
。然而,当您确实明确打算永不更改变量时,将其设置为 final
通常是一种很好的做法,因为这不仅会针对拼写错误或其他错误强制执行不变量,而且还会声明它的意图对其他程序员或您自己不可变。
如果变量是 public
,那么您将严格需要将其设为 final
以确保接口代码无法更改其值。
请注意,您 link 的问题没有直接关系,但是,因为它讨论 classes 即 final
,而不是变量。使 class final
意味着它不能被继承,而不是它是不可变的。但是,在制作不可变对象时,当然有必要注意该问题的内容及其答案;但这仍然是一个 单独的 问题。
通过标记 class 的所有字段 final
,您明确表示您希望 class 不可变。
假设您有以下 class:
public class Immutable {
private int value;
public Immutable (int value) {
this.value = value;
}
public int getValue () {
return value;
}
}
没有 setter 方法,因此可以很容易地假设此 class 是不可变的。现在是这样。但最终你的 class 会被其他程序员修改,这个程序员可能会在你的 class:
中添加一些方法
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
,他的修改是否破坏了 this 的契约class.
有人可能会争辩说应该使用 Javadoc 来记录说 class 是不可变的,但坦率地说,并不是每个人都阅读 Javadoc。我认为让代码自己说话更好。
之前的回答是错误的
要成为不可变对象,必须将所有属性声明为 final
。
Java 内存模型为 final 字段提供了某些保证,以防止它们在线程之间存在数据竞争时返回不正确的默认值。
参见 https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5-110 中的示例 17.5-2。
我阅读了 this question 有关不可变对象的内容,并留下了有关不可变对象和最终字段的问题:
为什么我们需要不可变 class 中的实例变量是最终的?
例如,考虑这个不可变的 class:
public final class Immutable
{
private final int someVal;
public Immutable(int someVal)
{
this.someVal= someVal;
}
public int getVal() {
return val;
}
}
如果上述代码中没有set方法,实例变量只在构造函数中设置,为什么要求实例变量声明为final?
在不可变 class 中,您无法更改其 property/field 的状态。通常它是通过不向 class 的客户端代码提供 setter 方法来完成的。
和static final
关键字的组合用于使变量常量。声明为 final 的变量一旦被初始化就永远不能改变它的值。
因为在不可变的 class 中你永远不需要改变 property/field 状态,所以最好让它成为最终状态。
没有要求 使变量final
。然而,当您确实明确打算永不更改变量时,将其设置为 final
通常是一种很好的做法,因为这不仅会针对拼写错误或其他错误强制执行不变量,而且还会声明它的意图对其他程序员或您自己不可变。
如果变量是 public
,那么您将严格需要将其设为 final
以确保接口代码无法更改其值。
请注意,您 link 的问题没有直接关系,但是,因为它讨论 classes 即 final
,而不是变量。使 class final
意味着它不能被继承,而不是它是不可变的。但是,在制作不可变对象时,当然有必要注意该问题的内容及其答案;但这仍然是一个 单独的 问题。
通过标记 class 的所有字段 final
,您明确表示您希望 class 不可变。
假设您有以下 class:
public class Immutable {
private int value;
public Immutable (int value) {
this.value = value;
}
public int getValue () {
return value;
}
}
没有 setter 方法,因此可以很容易地假设此 class 是不可变的。现在是这样。但最终你的 class 会被其他程序员修改,这个程序员可能会在你的 class:
中添加一些方法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
,他的修改是否破坏了 this 的契约class.
有人可能会争辩说应该使用 Javadoc 来记录说 class 是不可变的,但坦率地说,并不是每个人都阅读 Javadoc。我认为让代码自己说话更好。
之前的回答是错误的
要成为不可变对象,必须将所有属性声明为 final
。
Java 内存模型为 final 字段提供了某些保证,以防止它们在线程之间存在数据竞争时返回不正确的默认值。
参见 https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5-110 中的示例 17.5-2。