JVM核心之JVM運行和類加載全過程

 

爲何研究類加載全過程?java

  • 有助於鏈接JVM運行過程
  • 更深刻了解java動態性(解熱部署,動態加載),提升程序的靈活性

 

類加載機制數組

  • JVMclass文件加載到內存,並對數據進行校驗、解析和初始化,最終造成JVM能夠直接使用的java類型的全過程。

 

 

 

  • 加載
    • class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區中的運行時數據結構,在堆中生成一個表明這個類的java.lang.Class對象,做爲方法區類數據的訪問入口,這個過程須要類加載器參與。

 

 

 

  • 連接    java類的二進制代碼合併到JVM的運行狀態之中的過程
    •   驗證:確保加載的類信息符合JVM規範,沒有安全方面的問題
    •   準備:正式爲類變量(static變量)分配內存並設置類變量初始值的階段,這些內存都將在方法去中進行分配
    •   解析:虛擬機常量池的符號引用替換爲字節引用過程
  • 初始化
    • 初始化階段是執行類構造器<clinit>()方法的過程。類構造器<clinit>()方法是由編譯器自動收藏類中的全部類變量的賦值動做和靜態語句塊(static)中的語句合併產生
    • 當初始化一個類的時候,若是發現其父類尚未進行過初始化,則須要先觸發其父類的初始化
    • 虛擬機會保證一個類的<clinit>()方法在多線程環境中被正確加鎖和同步
    • 當範圍一個Java類的靜態域時,只有真正聲名這個域的類纔會被初始化

 

 

1安全

public class Demo01 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.width);
    }
}

class A{
    public static int width=100; //靜態變量,靜態域 field
    static{
        System.out.println("靜態初始化類A");
        width = 300 ;
    }
    public A() {
        System.out.println("建立A類的對象");
    }
}

 

分析:數據結構

說明:多線程

內存中存在棧、堆(放建立好的對象)、方法區(實際也是一種特殊堆)spa

1JVM加載Demo01時候,首先在方法區中造成Demo01類對應靜態數據(類變量、類方法、代碼),同時在堆裏面也會造成java.lang.Class對象(反射對象),表明Demo01類,經過對象能夠訪問到類二進制結構。而後加載變量A類信息,同時也會在堆裏面造成a對象,表明A類。線程

2main方法執行時會在棧裏面造成main方法棧幀,一個方法對應一個棧幀。若是main方法調用了別的方法,會在棧裏面挨個往裏壓,main方法裏面有個局部變量A類型的a,一開始a值爲null,經過new調用類A的構造器,棧裏面生成A()方法同時堆裏面生成A對象,而後把A對象地址付給棧中的a,此時a擁有A對象地址。code

3、當調用A.width時,調用方法區數據。對象

 

當類被引用的加載,類只會加載一次blog

  • 類的主動引用(必定會發生類的初始化)
    • new一個類的對象
    • 調用類的靜態成員(除了final常量)和靜態方法
    • 使用java.lang.reflect包的方法對類進行反射調用
    • 當虛擬機啓動,java Demo01,則必定會初始化Demo01類,說白了就是先啓動main方法所在的類
    • 當初始化一個類,若是其父類沒有被初始化,則先初始化它父類
  • 類的被動引用(不會發生類的初始化)
    • 當訪問一個靜態域時,只有真正聲名這個域的類纔會被初始化
      • 經過子類引用父類的靜態變量,不會致使子類初始化
    • 經過數組定義類的引用,不會觸發此類初始化
    • 引用常量不會觸發此類的初始化(常量在編譯階段就存入調用類的常量池中了)

例2:

public class Demo01 {
    static{
        System.out.println("靜態初始化Demo01");
    }
    
    
    public static void main(String[] args) throws Exception {
        System.out.println("Demo01的main方法!");
        System.out.println(System.getProperty("java.class.path"));
        
        //主動引用
//        new A();
//        System.out.println(A.width);
//        Class.forName("com.sinosoft.test.A");
        
        
        //被動引用
//        System.out.println(A.MAX);
//        A[] as = new A[10];
        System.out.println(B.width);//B類不會被加載
        
    }
}

class B  extends A {
    static {
        System.out.println("靜態初始化B");
    }
}

class A extends A_Father {
    public static int width=100;   //靜態變量,靜態域    field
    public static final  int MAX=100; 
    
    static {
        System.out.println("靜態初始化類A");
        width=300;
    }
    public A(){
        System.out.println("建立A類的對象");
    }
}

class A_Father extends Object {
    static {
        System.out.println("靜態初始化A_Father");
    }
}
相關文章
相關標籤/搜索