《深入理解JVM》7-類加載

從Class文件到類的過程要經過

  1. 加載-
  2. 鏈接-
  3. 初始化

三個過程。根據上一節講到的內容,java語言中分爲基本類型和引用類型

基本類型是虛擬機預先定義好的,引用類型分爲數組-類-接口。數組也是虛擬機直接生成的,只有類和接口對應的是字節流(操作碼流)

操作碼可以是class文件形式,也可以是網絡上讀取,也可以是機器內部生成。我們以常見的class文件爲例。

加載

查找類文件,並讀取字節碼到內存

雙親委派機制

jvm提供了默認的三個類加載器

  1. 啓動類加載器(boot strap classLoader),最頂級,是C++代碼實現,所以獲取不到,null代替。加載jre路徑下 lib目錄下的類
  2. 擴展類加載器(extension class loader),啓動類加載器的子類,加載 jre下lib/ext目錄下的類
  3. 應用類加載器 (application class loader),擴展類加載器的子類,加載應用相關的jar包等。

比如有這樣一個需求,需要加載com.david.study.test.Demo.class文件。首先獲取當前線程的類加載器A,然後逐級向上查找父加載器,看父加載器能否加載到Demo文件,如果可以,給內存中的Demo類取唯一符號:類加載器+類全路徑名。如果父加載器加載不到類,就自己取查找文件。

注意:如果一個類被不同的加載器加載,jvm會認爲兩個類不是同一個類。用戶也可以自定義類加載器

鏈接

  1. 驗證:驗證class字節碼是否符合虛擬機標準(版本號,magic no等)

  2. 準備:準備給類的靜態變量分配存儲空間,構建實現虛方法動態綁定的方法表。還有調用本類的方法和屬性,並不知道具體的地址,所以只能保存爲目標類的名稱+方法+參數+返回值這樣組成的符號引用,

  3. 解析:把字節碼當中的符號引用解析爲實際地址,比如調用B對象的update方法,之前只知道update的符號地址,現在要解析爲jvm中B類update的實際地址。

初始化

類中的靜態字段或靜態代碼段,在初始化階段給予賦值及執行,這些被集中放置在<clinit>方法中。java虛擬機在執行<clinit>方法時會加鎖,保證只執行一次。

調用初始化的時機:

  1. 程序啓動時,初始化主類
  2. new 命令
  3. 訪問靜態方法或靜態屬性
  4. 子類初始化會出發父類初始化
  5. 使用Api反射
  6. MethodHandle實例執行時