1. 程式人生 > >類載入順序,JVM角度分析理解,類構造器方法以及例項構造器方法執行順序

類載入順序,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>方法。介面的實現類也是一樣的。