類加載順序,JVM角度分析理解,類構造器方法以及實例構造器方法執行順序

今天先來分析一下經常遇到的一個問題,在筆試面試中可能會經常遇見,類中字段代碼塊的加載順序等,從jvm角度分析一下這個問題。我們先來看下知識點,接下來進行代碼實踐驗證。

  1. <clinit>,類構造器方法,在jvm第一次加載class文件時調用,因爲是類級別的,所以只加載一次,是編譯器自動收集類中所有類變量(static修飾的變量)和靜態語句塊(static{}),中的語句合併產生的,編譯器收集的順序,是由程序員在寫在源文件中的代碼的順序決定的。
  2. <init>,實例構造器方法,在實例創建出來的時候調用,包括調用new操作符;調用Class或java.lang.reflect.Constructor對象的newInstance()方法;調用任何現有對象的clone()方法;通過java.io.ObjectInputStream類的getObject()方法反序列化。
  • 邊驗證,邊解析

public class Main {
 
 
       //實例化代碼塊.每次生成類實例,都會執行.並且,實例化代碼塊的執行 優先於 構造器.
       {
            System.out.println("blockA");
       }
 
       //靜態語句塊,在類初始化時,僅僅執行一次.
        static{
            System.out.println("blockB");
        }
 
        //類實例
        public static Main t1 = new Main();
 
        //構造器方法
        Main(){
            System.out.println("constructor");
        }
 
 
        public static void main(String[] args)
        {
            //類實例
            Main t2 = new Main();
        }
}

 輸出結果

blockB
blockA
constructor
blockA
constructor

結果分析: 首先在Main類調用main方法,符合虛擬機規定的5種立即進行初始化。初始化的過程就是執行類構造器方法的<clinit>過程,首先初始化static語句,接着初始化類變量t1,執行t1的實例代碼塊,t1構造器方法<init>,最後在執行main方法中t2實例化。在此過程中,<clinit>只有在class文件第一次被加載時執行,<init>每次實例化時都會被執行一次。

通俗易懂解釋就是,首先需要<clinit>完成類級別的變量和代碼塊的加載,在進行對象級別的加載信息。

  • 需要記住的幾點

1.<clinit>方法和類的構造函數不同,它不需要顯示調用父類的構造方法,虛擬機會保證子類的<clinit>方法執行之前,父類的此方法已經執行完畢,因此虛擬機中第一個被執行的<clinit>方法的類肯定是java.lang.Object

2、接口中不能使用static塊,但是接口仍然有變量初始化的操作,因此接口也會生成<clinit>方法。但接口和類不同的是,不會先去執行繼承接口的<clinit>方法,而是在調用父類變量的時候,纔會去調用<clinit>方法。接口的實現類也是一樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章