在我们的团队中,我们发现了一些奇怪的行为,我们使用了两者static和final限定词 这是我们的测试类:
public class Test {
public static final Test me = new Test();
public static final Integer I = 4;
public static final String S = "abc";
public Test() {
System.out.println(I);
System.out.println(S);
}
public static Test getInstance() { return me; }
public static void main(String[] args) {
Test.getInstance();
}
}
Run Code Online (Sandbox Code Playgroud)
当我们运行该main方法时,我们得到一个结果:
null
abc
Run Code Online (Sandbox Code Playgroud)
我会理解它是否null两次写入值,因为静态类成员的代码是从上到下执行的.
任何人都可以解释为什么会发生这种行为?
Mar*_*nik 109
以下是运行程序时采取的步骤:
main运行之前,Test必须通过按外观顺序运行静态初始化程序来初始化类.me字段,请开始执行new Test().I.由于字段类型是Integer,似乎编译时常量4变为计算值(Integer.valueOf(4)).此字段的初始化程序尚未运行,打印初始值null.S.由于它是使用编译时常量初始化的,因此将该值烘焙到引用站点中进行打印abc.new Test()完成,现在I执行初始化程序.课程:如果您依赖于急切初始化的静态单例,请将单例声明放在最后一个静态字段声明中,或者使用在所有其他静态声明之后发生的静态初始化程序块.这将使类完全初始化为单例的构造代码.
sie*_*fer 21
由于Integer数据类型,您有奇怪的行为.关于JLS 12.4.2静态字段按您编写的顺序初始化,但首先初始化编译时常量.
如果您不使用包装类型Integer而是int类型,则可以获得所需的行为.
Mar*_*ius 14
你的Test编译成:
public class Test {
public static final Test me;
public static final Integer I;
public static final String S = "abc";
static {
me = new Test();
I = Integer.valueOf(4);
}
public Test() {
System.out.println(I);
System.out.println("abc");
}
public static Test getInstance() { return me; }
public static void main(String[] args) {
Test.getInstance();
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,初始化Test之前调用的构造I函数.这就是为什么它打印"null"了I.如果你要为me和交换声明顺序I,你会得到预期的结果,因为I在调用构造函数之前会初始化.您还可以更改类型I从Integer到int.
因为4需要获得自动装箱(即包装在一个Integer对象中),所以它不是编译时常量,而是静态初始化程序块的一部分.但是,如果类型是int,则该数字4将是编译时常量,因此不需要显式初始化.因为"abc"是编译时常量,所以S按预期打印值.
如果你要更换,
public static final String S = "abc";
Run Code Online (Sandbox Code Playgroud)
用,
public static final String S = new String("abc");
Run Code Online (Sandbox Code Playgroud)
然后你会注意到输出S也是"null"如此.为什么会这样?出于同样的原因I也输出"null".像这些有文字,常数值(即字段不需要自动装箱,像String)与归因"ConstantValue"编译时属性,这意味着它们的价值可以简单地通过查看类的常量池来解决,而无需运行任何代码.
| 归档时间: |
|
| 查看次数: |
4002 次 |
| 最近记录: |