在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;
现在它是一个编译错误。期末考试是怎么进行的呢?
如果你让foo是静态的,你必须在类构造函数中初始化它(或者你定义它的内联),就像下面的例子。
类构造函数(不是实例):
private static final List foo;
static
{
foo = new ArrayList();
}
内联:
private static final List foo = new ArrayList();
这里的问题不是最终修饰符如何工作,而是静态修饰符如何工作。
final修饰符强制在调用构造函数完成之前对引用进行初始化(即必须在构造函数中初始化它)。
当你内联初始化一个属性时,它会在你为构造函数定义的代码运行之前初始化,所以你会得到以下结果:
如果foo是静态的,foo = new ArrayList()将在你为你的类定义的静态{}构造函数执行之前执行
如果foo不是静态的,foo = new ArrayList()将在运行构造函数之前执行
如果不内联初始化属性,final修饰符强制初始化它,并且必须在构造函数中初始化。如果你也有一个静态修饰符,你必须初始化属性的构造函数是类的初始化块:static{}。
您在代码中得到的错误来自于这样一个事实,即静态{}在加载类时运行,在您实例化该类的对象之前。因此,在创建类时,你还没有初始化foo。
可以将静态{}块视为Class类型对象的构造函数。在这里必须初始化静态final类属性(如果不是内联完成的话)。
注:
final修饰符仅对基本类型和引用保证const性。
当你声明一个final对象时,你得到的是该对象的最终引用,但对象本身不是常量。
当你声明一个final属性时,你真正实现的是,一旦你声明了一个特定目的的对象(就像你已经声明的final List),这个对象将被用于该目的:你不能将List foo更改为另一个List,但你仍然可以通过添加/删除项来改变你的List(你正在使用的List将是相同的,只是它的内容被改变了)。