public class Dog {
public static Dog dog = new Dog();
static final int val1 = -5;
static int val2 = 3;
public int val3;
public Dog() {
val3 = val1 + val2;
}
public static void main(String[] args) {
System.out.println(Dog.dog.val3);
}
}
输出为-5
从这个结果来看,val2
的初始化似乎是在dog
成员完成及其实例化之前。
为什么这个订单是这样的?
答案 0 :(得分:21)
如果你最后移动你的狗实例,你可能会发现输出变为-2
public class Dog {
static final int val1 = -5;// This is final, so will be initialized at compile time
static int val2 = 3;
public int val3;
public static Dog dog = new Dog();//move to here
public Dog() {
val3 = val1 + val2;
}
public static void main(String[] args) {
System.out.println(Dog.dog.val3);//output will be -2
}
}
最终字段(其值为编译时常量表达式)将首先初始化,然后其余字段将以文本顺序执行。
因此,在你的情况下,当初始化dog实例时,static int val2
(0)尚未初始化,而static final int val1
( - 5)则是最终的。
http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.4.2声明:
执行类变量初始值设定项和静态 类的初始值设定项,或接口的字段初始值设定项, 按文字顺序,好像它们是一个块,除外 最终的类变量和值为的接口的字段 编译时常量首先初始化
以下是http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2
的jdk7版本最终字段位于第6步:
然后,初始化最终的类变量和接口字段 其值为编译时常量表达式
而静态字段在步骤9:
接下来,执行类变量初始值设定项和静态 类的初始值设定项,或接口的字段初始值设定项, 按照文字顺序,好像它们只是一个块。
答案 1 :(得分:10)
变量声明序列。 static final int val1
首先被初始化,因为它是常量。但是static int val2
在0
实例化时仍为public static Dog dog = new Dog();
。
答案 2 :(得分:6)
发生了什么......
正在执行的第一行是public static Dog dog = new Dog();
。
现在,必须牢记两件事。
final int
使其成为编译时间常量。因此,-5
已经硬编码到您的代码中。
完成对新Dog()
的调用,并调用构造函数,将值设置为0
+ -5
= -5
。
将val2
更改为final
,然后您会看到差异(您将获得-2
作为答案。)
注意:静态字段初始化为遇到它们以及如何遇到它们。
答案 3 :(得分:4)
测试中的初始化序列;
static final int val1 = -5;
//常数为静态最终public static Dog dog = new Dog();
//然后'dog'初始化但其成员val2尚未初始化static int val2 = 3;
//最后'val2'被初始化此代码更改将输出-2
;
public class Dog {
//public static Dog dog = new Dog();
static final int val1 = -5;
static int val2 = 3;
public int val3;
public static Dog dog = new Dog(); //moved here
public Dog() {
val3 = val1 + val2;
}
public static void main(String[] args) {
System.out.println(Dog.dog.val3);
}
}
答案 4 :(得分:4)
所有静态变量都在一个单独的静态构造函数中初始化,该构造函数在类加载时执行。与代码中的apear顺序相同。你的例子被编译成这样的东西:
public class Dog {
public static Dog dog;
static final int val1 = -5;
static int val2;
public int val3;
static {
dog = new Dog();
val2 = 3;
}
public Dog() {
val3 = val1 + val2;
}
public static void main(String[] args) {
System.out.println(Dog.dog.val3);
}
}
这就是为什么类/实例变量的顺序很重要的原因。类构造函数执行在初始化结束时发生。常数在之前得到解决。有关更多信息,请参阅Creation of New Class Instances。