JVM之類的加載、連接與初始化


title: JVM之類的加載、連接與初始化
date: 2019-04-01
tags: java

JVM之類的加載、連接與初始化——2019-04-01

  1. 加載:查找並加載類的二進制數據
  2. 連接
  1. 驗證:確保被加載類的正確性
  2. 準備:爲類的靜態變量分配內存,並將其初始化爲默認值
  3. 解析:把類中的符號引用轉換爲直接引用
  1. 初始化:爲類的靜態變量賦予正確的初始值

如:

Class test{
     Public static int a=1;
}

在test類在被加載時,靜態變量a首先被分配內存,設置默認值a=0
接着在初始化過程中才被賦予正確的初始值a=1

Java程序對類的使用方式可分爲兩種
 主動使用
 被動使用
所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才能初始化他們

主動使用(七種)
 創建類的實例(new一個類對象)
 訪問某個類或接口的靜態變量,或者對該靜態變量賦值(對靜態變量取值賦值)
助記符 getstatic putstatic
 調用類的靜態方法 助記符 invokestatic
 反射(如Class.forName(“com.test.Test”))
 初始化一個類的子類
如:
Class Parent{}
Class Child extends Parent{}
當子類被初始化時,同時也標記着父類的主動使用,父類也會被初始化
 Java虛擬機啓動時被標明爲啓動類的類(Java Test)
 JDK1.7開始提供的動態語言支持
Java.lang.invoke.MethodHandle實例的解析結果REF_getStatic, REF_putStatic, REF_invokeStatic句柄對應的類沒有初始化,則初始化

除了以上七種情況,其它使用java類的方式都被看作是對類的被動使用,都不會導致類的初始化

類的加載
類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在內存中創建一個java.lang.Class對象(規範並未說明Class對象位於哪裏,大致上放在堆區,HotSpot虛擬機將其放在了方法區中)用來封裝類在方法區內的數據結構

加載.class文件的方式

 從本地系統中直接加載(ide工作區重啓加載項目即是如此)
 通過網絡下載.class文件
 從zip,jar等歸檔文件中加載.class文件
 從專有數據庫中提取.class文件
 將Java源文件動態編譯爲.class文件(如JSP中java代碼的編寫,實際上是轉化成了Servlet)

(主動使用)
測試代碼一

package com.lagoon.jvm.classloder;

public class MyTest1 {

    public static void main(String[] args) {
        System.out.println(MyChild1.str);
    }
}

class MyParent1{

    public static String str="hello world";

    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1{
    static {
        System.out.println("MyChild1 static block");
    }
}

測試結果
在這裏插入圖片描述

並沒有輸出MyChild1 static block
這種情況稱之爲對MyParent1的一個主動使用,但是並沒有對MyChild1進行主動使用
所以並不會對MyChild1進行初始化,也就不會執行靜態代碼塊

測試代碼二

package com.lagoon.jvm.classloder;

public class MyTest1 {

    public static void main(String[] args) {
        System.out.println(MyChild1.str2);
    }
}

class MyParent1{

    public static String str="hello world";

    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1{
    public static String str2="welcome...";
    static {
        System.out.println("MyChild1 static block");
    }
}

測試結果
在這裏插入圖片描述

此時在MyChild1中定義了一個str2,並在main方法中調用的str2,是對MyChild類的一次主動使用,自然會初始化,自然也就會執行靜態代碼塊,輸出語句
而對於爲什麼MyParent1也會輸出語句?
是因爲主動使用裏有一條
出初始化一個類的子類,那麼也就是這個父類也會被主動使用,進行一次初始化。
父類會進行先行初始化

測試總結:
對於一個靜態字段來說,只有直接定義了該字段的類纔會被初始化
當一個類在初始化時,要求其父類全部都已經初始化完畢
這就是問什麼輸出語句有先後順序

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