为什么实例变量是最终的?

时间:2015-03-23 20:52:21

标签: java immutability final

我阅读了关于不可变对象的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?

4 个答案:

答案 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。