在Java中,我们使用带有变量的final关键字来指定其不被更改的值。 但我看到你可以改变类的构造函数/方法的值。同样,如果变量是静态的,那么这是一个编译错误。

代码如下:

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }
  public static void main(String[] args) 
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

以上代码工作正常,没有错误。

现在将变量更改为静态:

private static final List foo;

现在它是一个编译错误。期末考试是怎么进行的呢?


当前回答

final关键字可以有两种不同的解释方式,这取决于它的使用对象:

值类型:对于int型,double型等,它将确保值不能改变,

引用类型:对于对象的引用,final确保引用永远不会改变,这意味着它总是引用同一个对象。它不能保证对象中被引用的值保持不变。

因此,final List<Whatever> foo;确保foo总是指向相同的列表,但该列表的内容可能会随着时间的推移而改变。

其他回答

final关键字可以有两种不同的解释方式,这取决于它的使用对象:

值类型:对于int型,double型等,它将确保值不能改变,

引用类型:对于对象的引用,final确保引用永远不会改变,这意味着它总是引用同一个对象。它不能保证对象中被引用的值保持不变。

因此,final List<Whatever> foo;确保foo总是指向相同的列表,但该列表的内容可能会随着时间的推移而改变。

final关键字表示变量只能初始化一次。在你的代码中,你只执行了一次final的初始化,所以条件是满足的。该语句执行foo的单独初始化。注意final != immutable,它只意味着引用不能改变。

foo = new ArrayList();

当你将foo声明为static final时,变量必须在类加载时初始化,并且不能依赖实例化(也就是调用构造函数)来初始化foo,因为静态字段必须在没有类实例的情况下可用。不能保证在使用静态字段之前已经调用了构造函数。

当你在静态final场景下执行你的方法时,Test类在实例化t之前被加载,此时foo没有实例化,这意味着它还没有初始化,所以foo被设置为所有对象的默认值,即null。此时,我假设您的代码在尝试向列表中添加项时抛出NullPointerException。

值得一提的是一些简单的定义:

类/方法

您可以将类的部分或全部方法声明为final,以指示该方法不能被子类覆盖。

变量

一旦final变量初始化,它总是包含相同的值。

Final基本上避免被任何东西(子类,变量“重赋”)覆盖/上写,这取决于情况。

Final关键字有很多种用法:

final类不能被子类化。 final方法不能被子类重写 final变量只能初始化一次

其他用途:

在方法体中定义匿名内部类时, 在该方法范围内声明为final的所有变量为 从内部类内部访问

静态类变量将从JVM开始时就存在,并且应该在类中初始化。如果您这样做,错误消息将不会出现。

阅读所有答案。

在另一个用户案例中,final关键字可以用在方法参数中:

public void showCaseFinalArgumentVariable(final int someFinalInt){

   someFinalInt = 9; // won't compile as the argument is final

}

可用于不应更改的变量。