在构造函数中,指定的最终对象字段是否仍然为空?
class MyClass {
private final Object obj = new Object();
public MyClass() {
System.out.println(obj); // may print null?
}
}
如果是,这不是一个错误吗?
答案 0 :(得分:5)
正如其他答案所讨论的那样,不,这不可能发生。但是,对于指定的最终静态字段,它可以。
class MyClass {
private static MyClass myClass = new MyClass();
private static final Object obj = new Object();
public MyClass() {
System.out.println(obj); // will print null once
}
}
答案 1 :(得分:3)
除了所有initializers run before the constructor is invoked之外,这是不可能的。
在调用构造函数之前,像private final Object obj = new Object();
一样运行变量初始化程序。初始化块静态或其他也是如此。
使用初始化程序时要注意的一点是初始化程序无法进行正向引用在编写初始化程序时,不能引用在初始化变量后以文本方式声明的任何实例变量。 / p>
答案 2 :(得分:2)
初始化程序Object obj = new Object();
将在构造函数内部的代码之前运行,因此obj
不能是null
。
请注意,如果您未在任何位置初始化obj
,则无法编译。
答案 3 :(得分:2)
适合我:
$ cat MyClass.java
class MyClass {
private final Object obj = new Object();
public MyClass() {
System.out.println(obj); // may print null?
}
public static void main(String[] args) { new MyClass(); }
}
$javac MyClass.java; java MyClass
java.lang.Object@19908ca1
所有字段初始值设定项都由编译器复制到所有构造函数的开头。
但是,在Java 5内存模型下,如果在构造函数结束之前让this
引用'转义',则其他线程可以看到final
字段的未初始化值(因此可以看到{在这种情况下{1}}。
答案 4 :(得分:2)
通过像你这样的简单例子,没有什么不好的事情可以发生。但是,如果您使用可疑的做法(例如在构造函数中调用可覆盖的方法),final
字段可以作为未初始化显示, 。
例如,以下程序打印“我最喜欢的颜色为空”,即使它引用了最终变量favouriteColour
,它在构造函数中设置为"blue"
。
abstract class SuperClass {
final String favouriteColour;
SuperClass() {
announceFavouriteColour();
favouriteColour = "blue";
}
abstract void announceFavouriteColour();
}
public class FinalTest extends SuperClass {
void announceFavouriteColour() {
System.out.println("My favourite colour is " + favouriteColour);
}
public static void main(String[] args) {
new FinalTest();
}
}