天天看點

JVM的類加載過程

  • 在Java代碼中,類型的加載、連接配接與初始化過程都是在程式運作期間完成的
  • 提供了更大的靈活性,增加了更多的可能性
  • Java虛拟機與程式的生命周期 在如下集中情況Java虛拟機會結束生命周期

    1、執行了system.exit()方法

    2、程式正常執行結束

    3、程式在執行過程中遇到了異常或錯誤而異常終止

    4、由于作業系統出現錯誤而導緻Java虛拟機程序終止

    類加載過程:加載、連接配接、初始化、使用、解除安裝

  • 加載:查找并加載類的二進制資料
  • 連接配接
    1. 驗證: 確定被加載的類的正确性
    2. 準備: 為類的靜态變量配置設定記憶體,并将其初始化為預設值 例public static int a =1 在準備階段時 會将int型的預設值0指派給他
    3. 解析:把類中的符号引用轉換為直接引用

      // 符号引用

      String str = “123”;

      sout(“str=”+str);

      // 直接引用

      sout(“str=”+”123”);

      符号引用要轉換成直接引用才有效,這也說明直接引用比符号引用效率高。那為什麼要用符号引用呢?這是因為類加載之前,javac會将源代碼編譯成.class檔案,這個時候javac是不知道被編譯的類中所引用的類、方法或者變量他們的引用位址在哪裡,是以隻能用符号引用來表示,當然,符号引用是要遵循java虛拟機規範的。

  • 初始化: 為類的靜态變量賦予正确的初始值 在此時會将靜态變量a原有的值指派給他
  • 使用
  • 解除安裝

    Java程式對類的使用方式

  • Java程式對類的使用方式可分為兩種
    1. 主動使用(七種)
      • 建立類的執行個體
      • 通路某個類或者接口的靜态變量,或者對該靜态變量指派
      • 調用類的靜态方法。(從助記符的層面上 第二種和第三種是類似的,通路是getstatic 指派是putstatic 調用是invokestatic)
      • 反射 class.forName
      • 初始化一個類的子類
      • Java虛拟機啟動時被标注為啟動類的類(Java Test)
      • JDK1.7開始提供的動态語言…(了解就行)
    2. 被動使用
      • 除了以上七種情況,其他使用Java類的方式都被看作是對類的被動使用,都不會導緻類的初始化
  • 所有的Java虛拟機實作必須在每個類或者接口被Java程式 首次主動使用 時才初始化他們

    類的加載

  • 類的加載指的是将類的.class檔案中的二進制資料讀入到記憶體中,将其放在運作時資料區的方法區内,然後在記憶體中建立一個java.lang.Class對象(規範并未說明Class對象位于哪裡,HotSpot虛拟機将其放在方法區中) 用來封裝類在方法區内的資料結構 (一個類無論被執行個體了多少次 它對應的Class對象隻有一個)
  • 加載.class檔案的方式
    1. 從本地系統中直接加載
    2. 通過網絡下載下傳.class檔案
    3. 從zip,jar等歸檔檔案中加載.class檔案
    4. 從專有資料庫中提取.class檔案
    5. 将Java源檔案動态為.class檔案(比如jsp servlet)

常量的本質含義

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      
public class MyTest {

    public static void main(String[] args) {
        /**
         * 常量在編譯階段會存入到調用這個常量到方法所在到類到常量池當中,
         * 本質上,調用類并沒有直接引用到定義常量的類,是以不會觸發定義常量到類的初始化
         */
        // 這裡是将常量str存到MyTest類當中,之後MyTest和MyParent2就沒有任何關系了,甚至可以把MyParent2到class檔案删除
        System.out.println(MyParent2.str);
    }
}

class MyParent2 {

    public static final String str = "hello world";

    static {
        System.out.println("MyParent2 ");
    }
}