这是一个最喜欢的面试问题。通过这个问题,面试官试图找出你对构造函数、方法、类变量(静态变量)和实例变量的对象行为的理解程度。
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 void setFoo(List foo) {
//this.foo = foo; Results in compile time error.
}
}
在上面的例子中,我们为“Test”定义了一个构造函数,并给了它一个“setFoo”方法。
关于构造函数:使用关键字每次创建对象 只能调用一次构造函数。new
您不能多次调用构造函数,因为构造函数不是为此而设计的。
关于方法:可以根据需要多次调用方法(甚至永远不会),并且编译器知道这一点。
方案 1
private final List foo; // 1
foo
是一个实例变量。当我们创建Test
类对象时,实例变量foo
将被复制到Test
类的对象中。如果我们foo
在构造函数内部赋值,那么编译器就知道构造函数只会被调用一次,所以在构造函数内部赋值没有问题。
如果我们foo
在一个方法内部赋值,编译器就知道一个方法可以被多次调用,这意味着值必须被多次改变,这对于一个final
变量是不允许的。所以编译器决定构造函数是不错的选择!您只能为最终变量赋值一次。
方案 2
private static final List foo = new ArrayList();
foo
现在是一个静态变量。当我们创建Test
类的实例时,foo
不会因为foo
是静态的而被复制到对象中。现在foo
不是每个对象的独立属性。这是Test
类的属性。但是foo
可以通过多个对象看到,如果使用new
关键字创建的每个对象最终都会调用Test
构造函数,该构造函数会在多个对象创建时更改值(记住static foo
不是在每个对象中复制,而是在多个对象之间共享.)
方案 3
t.foo.add("bar"); // Modification-2
以上Modification-2
来自你的问题。在上述情况下,您不会更改第一个引用的对象,而是在foo
其中添加允许的内容。如果您尝试将 a 分配new ArrayList()
给foo
引用变量,编译器会抱怨。
规则如果你已经初始化了一个final
变量,那么你不能改变它来引用一个不同的对象。(在这种情况下ArrayList
)
final类不能被子类化
final方法不能被覆盖。(此方法在超类中)
最终方法可以覆盖。(以语法方式阅读。此方法在子类中)