1. 程式人生 > >Java類、實例初始化的順序

Java類、實例初始化的順序

++ 變量 相關 obi 類加載的過程 經歷 過程 stat 布局

求如下 java 代碼的輸出??
class T  implements Cloneable{
  public static int k = 0;
  public static T t1 = new T("t1");
  public static T t2 = new T("t2");
  public static int i = print("i");
  public static int n = 99;
  
  public int j = print("j");
  {
      print("構造快");
  }
  
  static {
      print("靜態塊");
  }
  
  
public T(String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++n; ++ i; } public static int print(String str){ System.out.println((++k) +":" + str + " i=" + i + " n=" + n); ++n; return ++ i; } public static void main(String[] args){ T t
= new T("init"); } }

分析:

代碼主要考察類、變量初始化的順序

一般的,我們很清楚類需要在被實例化之前初始化,而對象的初始化則是運行構造方法中的代碼。

代碼組成:

  • 成員變量 2~6 行的變量是 static 的,為類 T 的靜態成員變量,需要在類加載的過程中被執行初始化;第 8 行的int j則為實例成員變量,只再類被實例化的過程中初始化。

  • 代碼段 9~11 行為實例化的代碼段,在類被實例化的過程中執行;13~15 行為靜態的代碼段,在類被加載、初始化的過程中執行。

  • 方法 方法public static int print(String str)

    為靜態方法,其實現中牽涉到 k,i,n 三個靜態成員變量,實際上,這個方法是專門用來標記執行順序的方法;T 的構造方法是個實例化方法,在 T 被實例化時調用。

  • main 方法 main 方法中實例化了一個 T 的實例。

執行順序分析:

在一個對象被使用之前,需要經歷的過程有:類的裝載 -> 鏈接(驗證 -> 準備 -> 解析) -> 初始化 -> 對象實例化。(詳情參見《Java 類的裝載、鏈接和初始化》),這裏需要註意的點主要有:

  • 在類鏈接之後,類初始化完成之前,實際上類已經可以被實例化了。

就如此題代碼中所述,在眾多靜態成員變量被初始化完成之前,已經有兩個實例的初始化了。實際上,此時對類的實例化,除了無法正常使用類的靜態成員變量以外(還沒有保證完全被初始化),JVM 中已經加載了類的內存結構布局,只是沒有執行初始化的過程。比如第 3 行public static T t1 = new T("t1");,在鏈接過程中,JVM 中已經存在了一個 t1,它的值為 null,還沒有執行new T("t1")。又比如第 5 行的public static int i = print("i");,在沒有執行初始化時,i 的值為 0,同理 n 在初始化前值也為 0.

  • 類實例化的過程中,先執行父類的構造器,然後執行隱式的構造代碼,再執行構造方法中的代碼

實際上,在編譯 Java 代碼到字節碼的過程中,編譯器已經將源碼中實例化相關的代碼集中到了構造方法中。

這裏隱式的構造代碼包括了{}代碼塊中的代碼,以及實例成員變量聲明中的初始化代碼。它們的執行順序以源代碼中代碼出現的順序為準。為何不是先執行顯示的構造方法中的代碼,再執行隱式的代碼呢?這也很容易解釋:構造方法中可能就需要使用到實例成員變量,而這時候,我們是期待實例變量能正常使用的。

有了如上的分析,也就能推到出最終的輸出結果了。實際上,這幾個原則都不需要死記硬背,完全能通過理解整個 JVM 的執行過程來梳理出思路的。

答案:

1:j   i=0   n=0
2:構造快   i=1   n=1
3:t1    i=2  n=2
4:j   i=3   n=3
5:構造快   i=4   n=4
6:t2    i=5  n=5
7:i   i=6   n=6
8:靜態塊   i=7   n=99
9:j   i=8   n=100
10:構造快   i=9   n=101
11:init    i=10  n=102

轉自:http://biaobiaoqi.github.io/blog/2013/09/22/java-initialization/

Java類、實例初始化的順序