1. 程式人生 > >淺談類初始化與物件例項化

淺談類初始化與物件例項化

類的初始化和物件的例項化

類的初始化是指類和介面載入到方法區後,因某些原因的觸發,執行靜態變數初始化語句和靜態初始化塊中語句的過程,初始化語句的執行順序是由上往下的。 類的初始化語句由編譯器 收集並放到一個特殊的方法中,稱為類初始化方法,在Class檔案中對應的是<clinit>,這種只方法只能由JVM呼叫。 觸發類初始化方法的條件可以包括: 1.建立本類物件或子類物件。包括使用new操作符建立物件、通過反射(Class類的newInstance方法、Constructor類的newInstance方法)。 2.訪問靜態成員。包括對靜態變數的賦值和讀取,但不包括對常量的訪問,呼叫靜態方法。
3.Class.forName方法。 4.子類初始化。 5.Java應用程式的入口,即應用程式啟動時執行的主類。 特殊情況: 通過子類呼叫父類的靜態變數只會觸發父類的初始化。 直接呼叫class物件而不用於訪問類的結構是不會觸發類的初始化,因為該物件是類在裝載時在堆記憶體建立的。 介面不能定義static塊,同時子介面的初始化不會觸發父介面的初始化。 實現類在不呼叫介面成員的情況下不會初始化介面。 初始化類的過程必須保持同步,如果有多個執行緒初始化一個類,僅僅允許一個執行緒執行初始化,其他的執行緒都需要等待。
物件的例項化是指使用new建立物件和呼叫構造方法初始化物件的過程,發生在類初始化之後。構造方法在Class檔案中被編譯成<init>,每個構造器都會先執行例項變數的初始化語句,意思是例項變數宣告的語句中的賦值。
public class C { String name = "default"; public C(String name) { this.name = name; } } 構造方法的位元組碼將如下: public jptest.C(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #3                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: ldc           #4                  // String default
         7: putfield      #5                  // Field name:Ljava/lang/String;
        10: aload_0
        11: ldc           #6                  // String init
        13: putfield      #5                  // Field name:Ljava/lang/String;
        16: aload_0
        17: aload_1
        18: putfield      #5                  // Field name:Ljava/lang/String;
        21: return

由此可以得知例項化一個物件,程式碼執行的順序是:靜態初始化塊->父類構造方法->例項初始化塊->例項變數初始化語句->構造方法的程式碼。