標籤:field 儲存 java chm .class 操作 重寫 避免 擷取
類的載入過程
一,載入
定義:擷取.class檔案的位元組流,轉為方法區的資料結構,在記憶體中建立Class對象作為該類的資料訪問入口
內容:【1】,根據類的全限定名擷取二進位位元組流
【2】,根據位元組流代表的靜態儲存結構轉化為方法區的運行時資料結構
【3】,在記憶體中產生該類的java.lang.Class對象,作為方法區該類的資料訪問入口(註:記憶體指的不一定是堆, 如HotSpot虛擬機器是存放在方法區)
從.class檔案擷取位元組流方式:
【1】,zip包讀取 如:jar,ear,war等格式檔案
【2】,網路擷取 如:Applet
【3】,運行時計算產生 如:動態代理,java.lang.reflect.Proxy中使用ProxyGenerator.generateProxyClass為特定介面產生形式為"*$Proxy"的代理類的二進位位元組流
【4】,其他檔案 如:jsp檔案產生對應的Class類
【5】,資料庫 如:中介軟體伺服器SAP Netweaver
其他:
①,類載入過程中,在記憶體中建立Class對象,這裡的記憶體不一定是堆記憶體,根據虛擬機器而定,如:HotSpot虛擬機器是存放在方法區
②,載入階段和串連階段交叉進行,載入未結束串連階段的位元組碼驗證可能就開始了
③,類載入可以分為非數組類和數組類載入
非數組類:通過1,系統提供的類載入器 2,使用者自訂的類載入器(重寫類載入器的loadClass方法)
數組類:不使用類載入器建立,由虛擬機器直接建立
數組類建立規則:1.如果數組組件是參考型別,數組會在載入該參考型別的類載入器的類名稱上進行標識
2.如果數組組件不是參考型別,java虛擬機器將數組標記為和引導類載入器關聯
3.數組可見度和它的組件類型一致,如不是不是參考型別預設是public
二,驗證(串連)
定義:對Class檔案的位元組流包含的資訊進行驗證是否符合虛擬機器要求,避免危害虛擬機器安全
為什麼需要驗證:Class檔案不一定都是Java源碼編譯而來,例如:使用十六進位編輯器直接編寫Class檔案,而這些非Java源碼編譯而來的Class檔案不一定格式正確
內容:【1】,檔案格式驗證 (檔案)
檢查位元組流是否符合Class檔案格式規範,是否能被目前的版本的虛擬機器處理
如: ①,是否已魔數0xCAFEBABE開頭
②,主次版本是否在當前虛擬機器處理範圍之內
③,常量池是否有不支援的常量類型
④,指向常量的索引值是否指向不存在的常量和不符合類型的常量
⑤,CONSTANT_Utf8_info型的常量是否符合UTF8編碼
... ...
【2】,中繼資料驗證 (資料類型)
對位元組碼資訊進行語義分析,是否符合Java語言規範
如:①,是否有父類(除java.lang.Object)
②,父類是否繼承了不允許被繼承的類(final修飾類)
③,非抽象類別是否實現了父類和介面中要求實現的所有方法
④,類的欄位和方法是否和父類出現衝突(如:覆蓋父類final欄位,錯誤的重載等)
... ...
【3】,位元組碼驗證 (方法)
通過資料流和控制流程分析,確定程式語義是否合法
如:①,運算元棧的資料類型與指令代碼序列都能配合工作不會出現類型不一致的情況
②,跳轉指令不會跳轉到方法體外
③,方法體內的類型轉換是有效,如將父類對象賦值給子類資料類型是不合法的
關閉StackMapTable對於位元組碼驗證最佳化配置:
-XX:-UseSplitVerifier
-XX:+FailOverToOldVerifier
【4】,符號引用驗證
對類自身以外的資訊進行匹配性校正
目的:確保解析動作能正常執行
發生的時間:解析階段中虛擬機器將符號引用轉為直接引用的時候進行符號引用驗證
校正內容:①,符號引用中通過字串描述的全限定名是否能找到對應的類
②,指定類中是否存在符合方法的欄位描述符以及簡單名稱所描述的方法和欄位
③,符號引用中的類,欄位,方法的訪問性是否可被當前類訪問
... ...
可能的錯誤:java.lang.NoSuchFieldError, java.lang.NoSuchMethodError等
三,準備(串連)
定義:為類的靜態變數在方法區分配記憶體,設定初始零值
其他:
public static final int value = 123; //準備階段:設定為123
public staitc int value = 123; //準備階段:設定為0,將value賦值為123的putstatic指令編譯後存放於類構造器<clinit>()方法中, 初始化階段:設定為123
JAVA-類載入機制(2)-類載入的過程