带有静态和最终限定符的奇怪Java行为
在我们的团队中,我们发现了一些奇怪的行为,我们使用了带有静态和最终限定符的奇怪Java行为,java,final,Java,Final,在我们的团队中,我们发现了一些奇怪的行为,我们使用了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)
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();
}
}
当我们运行main
方法时,我们得到以下结果:
null
abc
如果它两次都写null
值,我会理解,因为静态类成员的代码是从上到下执行的
有人能解释为什么会发生这种行为吗?
S
是一个编译时常量,遵循编译规则。因此,代码中出现的任何S
都将替换为编译时已知的值
如果将
I
的类型更改为int
,您也会看到同样的情况。以下是运行程序时采取的步骤:
main
之前,必须通过按出现顺序运行静态初始值设定项来初始化Test
类me
字段,请开始执行newtest()
I
的值。由于字段类型为Integer
,因此编译时常量4
将成为计算值(Integer.valueOf(4)
)。此字段的初始值设定项尚未运行,正在打印初始值null
S
的值。因为它是用编译时常量初始化的,所以该值被烘焙到引用站点中,打印abc
newtest()
完成,现在执行I
的初始值设定项教训:如果您依赖于急切初始化的静态单例,请将单例声明作为最后一个静态字段声明,或者求助于在所有其他静态声明之后出现的静态初始值设定项块。这将使类看起来完全初始化为单例的构造代码。由于数据类型为
Integer
,您会有奇怪的行为。静态字段是按照您编写它的顺序初始化的,但编译时常量是先初始化的
如果不使用包装器类型
Integer
而使用int
类型,则可以获得所需的行为。您的测试编译为:
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();
}
}
如您所见,Test
的构造函数在初始化I
之前被调用。这就是它为I
打印的原因。如果将声明顺序交换为me
和I
,则会得到预期的结果,因为I
将在调用构造函数之前初始化。您还可以将I
的类型从Integer
更改为int
因为4
需要自动装箱(即,包装在整数
对象中),所以它不是编译时常量,是静态初始值设定项块的一部分。但是,如果类型为int
,则编号4
将是编译时常量,因此不需要显式初始化。由于“abc”
是一个编译时常量,因此S
的值按预期打印
如果你愿意替换
public static final String S = "abc";
有,
然后您会注意到S
的输出也是“null”
。为什么会这样?出于同样的原因,I
也会输出“null”
。此类字段具有文本常量值(不需要自动装箱,如String
)在编译时使用“ConstantValue”
属性进行属性化,这意味着只需查看类的常量池即可解析其值,而无需运行任何代码。相关(和)你可以看看答案。希望有帮助。另一个混乱归因于Java的特权类型。现在标记为重复…这是新闻稿的效果吗?确定吗?我希望System.out.println(“abc”)代码>,而不是System.out.println代码>,因为编译器内联编译时常量。你说得对。在前一种情况下,将有一条ldc
指令,而不是getstatic
。这就是我在最后一句话中想表达的意思,我想我应该澄清一下。你的代码应该表明这一点,因为你说过OPs是编译成这个的。@Tom,这是一个没有区别的区别S
是“abc”
@EJP的另一个名称,这里可能没有,因为声明和访问都在同一个类中,但如果它们在不同的类中,则必须将它们区分开来。
public static final String S = new String("abc");