簡體   English   中英

為什么字段似乎在構造函數之前被初始化?

[英]Why do fields seem to be initialized before constructor?

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

為什么這個訂單是這樣的?

如果你最后移動你的狗實例,你可能會發現輸出變為-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)因為它是final而執行。

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:

接下來,按文本順序執行類的類變量初始值設定項和類的靜態初始值設定項,或接口的字段初始值設定項,就好像它們是單個塊一樣。

變量聲明序列。 static final int val1首先被初始化,因為它是一個常量。 但是static int val2public static Dog dog = new Dog();時仍為0 public static Dog dog = new Dog(); 被實例化。

怎么了..

正在執行的第一行是這個public static Dog dog = new Dog(); 現在,必須牢記兩件事。

  1. final int使它成為編譯時常量。 因此, -5已經硬編碼到您的代碼中。

  2. 完成對新Dog()的調用並調用構造函數,將值設置為0 + -5 = -5

val2更改為final然后您將看到差異(您將得到-2作為答案。)

注意:靜態字段初始化為以及如何遇到它們。

測試中的初始化順序;

  1. static final int val1 = -5; //常數為靜態最終
  2. public static Dog dog = new Dog(); //然后'dog'初始化但其成員val2尚未初始化
  3. 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);

    }
}

所有靜態變量都在一個單獨的靜態構造函數中初始化,該構造函數在類加​​載時執行。 與代碼中的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);
 }
}

這就是為什么類/實例變量的順序很重要的原因。 類構造函數執行在初始化結束時發生。 常數在之前得到解決。 有關更多信息,請參閱創建新類實例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM