1. 程式人生 > >與 與 類的初始化順序

與 與 類的初始化順序

這兩種方法有什麼區別呢?

首先:這兩個方法一個是虛擬機器在裝載一個類初始化的時候呼叫的(clinit)。另一個是在類例項化時呼叫的(init)

首先說說類的初始化:

在Java程式碼中,一個正確的初始值是通過類變數初始化語句或者靜態初始化語句給出的。一個類變數初始化語句是

變數聲明後的等號和表示式:

Java程式碼  收藏程式碼
  1. class Example {  
  2.        static int size = 3 * (int) (Math.random() * 5.0);  
  3. }  

靜態初始化語句是一個以static開頭的語句塊:

Java程式碼  收藏程式碼
  1. class Example{  
  2.      static int size;  
  3.      static {  
  4.            size = 3 * (int) (Math.random() * 5.0);  
  5.      }  
  6. }  

 所有的類變數初始化語句和型別的靜態初始化語句都被Java編譯器收集到了一起,放在一個特殊的方法中。這個方法就是<clinit>

我們在來看看<init>這個方法:

<init>方法是在一個類進行物件例項化時呼叫的。例項化一個類有四種途徑:呼叫new操作符;呼叫Class或java.lang.reflect.Constructor物件的newInstance()方法;呼叫任何現有物件的clone()方法;通過java.io.ObjectInputStream類的getObject()方法反序列化。

Java編譯器會為它的每一個類都至少生成一個例項初始化方法。在Class檔案中,被稱為"<init>"

現在知道了吧, 一個是用於初始化靜態的類變數, 一個是初始化例項變數!

<init><clinit>

<init>

Java在編譯之後會在位元組碼檔案中生成<init>方法,稱之為例項構造器,該例項構造器會將語句塊,變數初始化,呼叫父類的構造器等操作收斂到<init>方法中,收斂順序(這裡只討論非靜態變數和語句塊)為: 
1. 父類變數初始化 
2. 父類語句塊 
3. 父類建構函式 
4. 子類變數初始化 
5. 子類語句塊 
6. 子類建構函式

所謂收斂到<init>方法中的意思就是,將這些操作放入到<init>中去執行

<clinit> 
Java在編譯之後會在位元組碼檔案中生成<clinit>方法,稱之為類構造器,類構造器同例項構造器一樣,也會將靜態語句塊,靜態變數初始化,收斂到<clinit>方法中,收斂順序為: 
1. 父類靜態變數初始化 
2. 父類靜態語句塊 
3. 子類靜態變數初始化 
4. 子類靜態語句塊

<clinit>方法是在類載入過程中執行的,而<init>是在物件例項化執行的,所以<clinit>一定比<init>先執行。所以整個順序就是: 
1. 父類靜態變數初始化 
2. 父類靜態語句塊 
3. 子類靜態變數初始化 
4. 子類靜態語句塊 
5. 父類變數初始化 
6. 父類語句塊 
7. 父類建構函式 
8. 子類變數初始化 
9. 子類語句塊 
10. 子類建構函式

初始化順序

如下父類程式碼

public class Parent {
    static int a = 1;
    int b = 1;
    static {
        System.out.println("parent static block(a):" + (++a));
    }
    {
        System.out.println("parent  block(b):" + (++b));
    }
    public Parent() {
        System.out.println("parent construction");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

子類程式碼

public class Child extends Parent {
    static int a = 1;
    int b = 1;
    static {
        System.out.println("child static block(a):" + (++a));
    }
    {
        System.out.println("child  block(b):" + (++b));
    }
    public Child() {
        System.out.println("child construction");
    }
    public static void main(String[] args) {
        new Child();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

最終輸出結果為

parent static block(a):2
child static block(a):2
parent  block(b):2
parent construction
child  block(b):2
child construction
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6