为什么字段似乎在构造函数之前被初始化?

时间:2014-12-10 06:55:45

标签: java output

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成员完成及其实例化之前。

为什么这个订单是这样的?

5 个答案:

答案 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 val20实例化时仍为public static Dog dog = new Dog();

答案 2 :(得分:6)

发生了什么......

正在执行的第一行是public static Dog dog = new Dog();。 现在,必须牢记两件事。

  1. final int使其成为编译时间常量。因此,-5已经硬编码到您的代码中。

  2. 完成对新Dog()的调用,并调用构造函数,将值设置为0 + -5 = -5

    < / LI>

    val2更改为final,然后您会看到差异(您将获得-2作为答案。)

    注意:静态字段初始化为遇到它们以及如何遇到它们。

答案 3 :(得分:4)

测试中的初始化序列;

  1. static final int val1 = -5; //常数为静态最终
  2. public static Dog dog = new Dog(); //然后'dog'初始化但其成员val2尚未初始化
  3. static int val2 = 3; //最后'val2'被初始化
  4. 此代码更改将输出-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