java类加载过程_面试官:java类的加载过程
Java 類加載機制
類從被加載到JVM中開始,到卸載為止,整個生命周期包括:加載、驗證、準備、解析、初始化、使用和卸載七個階段。
其中類加載過程包括加載、驗證、準備、解析和初始化五個階段。
類的加載過程圖
類的加載過程
加載
1、通過類加載器,加載.class文件到內存中。
2、將讀取到.class數據存儲到運行時內存區的方法區。
3、然后將其轉換為一個與目標類型對應的java.lang.Class對象實例。這個Class對象在日后就會作為方法區中該類的各種數據的訪問入口。
鏈接
驗證
確保被加載的類(.class文件的字節流),是否按照java虛擬的規范。不會造成安全問題
1、文件格式驗證:
第一階段要驗證字節流是否符合 Class文件格式的規范, 井且能被當前版本的虛擬機處理。這一階段可能包括下面這些驗證點:
- 是否以魔數 0xCAFEBABE開頭
- 主、次版本號是否在當前虛擬機處理范圍之內 。
- 常量池的常量中是否有不被支持的常量類型(檢查常量tag 標志)。
- 指向常量的各種索引值中是否有指向不存在的常量或不符合裝型的常量 。
- CONSTANT_Utf8_info型的常量中是否有不符合 UTF8編碼的數據
- Class 文件中各個部分及文件本身是否有被刪除的或附加的其他信息
實際上第一階段的驗證點還遠不止這些, 這是其中的一部分。只有通過了這個階段的驗證之后, 字節流才會進入內存的方法區中進行存儲, 所以后面的三個驗證階段全部是基于方法區的存儲結構進行的,不會再直接操作字節流。
2、元數據驗證
第二階段是對字節碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規范的要求,這個階段可能包括的驗證點如下:
- 這個類是否有父類(除了java.lang.0bject之外,所有的類都應當有父類)
- 這個類的父類是否繼承了不允許被繼承的類(被finaI修飾的類)
- 如果這個類不是抽象類, 是否實現了其父類或接口之中要求實現的所有方法
- 類中的字段、 方法是否與父類產生了矛盾(例如覆蓋了父類的final字段, 或者出現不符合規則的方法重載, 例如方法參數都一致, 但返回值類型卻不同等)
第二階段的驗證點同樣遠不止這些,這一階段的主要目的是對類的元數據信息進行語義檢驗, 保證不存在不符合 Java語言規范的元數據信息。
3、字節碼驗證
第三階段是整個驗證過程中最復雜的一個階段, 主要目的是通過數據流和控制流的分析,確定語義是合法的。符號邏輯的。在第二階段對元數據信息中的數據類型做完校驗后,這階段將對類的方法體進行校驗分析,保證被校驗類的方法在運行時不會做出危害虛擬機安全的行為,例如:
- 保證任意時刻操作數棧的數據裝型與指令代碼序列都能配合工作, 例如不會出現類似這樣的情況:在操作棧中放置了一個 int類型的數據, 使用時卻按long類型來加載入本地變量表中。
- 保證跳轉指令不會跳轉到方法體以外的字節碼指令上
- 保證方法體中的類型轉換是有效的, 例如可以把一個子類對象賦值給父類數據裝型,這是安全的,但是把父類對象意賦值給子類數據類型,甚至把對象賦值給與它毫無繼承關系、 完全不相干的一個數據類型, 則是危險和不合法的。
即使一個方法體通過了字節碼驗證, 也不能說明其一定就是安全的。
4、符號引用驗證
最后一個階段的校驗發生在虛擬機將符號引用轉化為直接引用的時候 , 這個轉化動作將在連接的第三個階段——解析階段中發生。符號引用驗證可以看做是對類自身以外(常量池中的各種符號引用) 的信息進行匹配性的校驗, 通常需要校驗以下內容:
- 符號引用中通過字將串描述的全限定名是否能找到對應的類
- 在指定類中是否存在符合方法的字段描述符以及簡單名稱所描述的方法和字段 。
- 符號引用中的類、字段和方法的訪問性(private、 protected、 public)是否可被當前類訪問
符號引用驗證的目的是確保解析動作能正常執行, 如果無法通過符號引用驗證, 將會拋出一個java.lang.IncompatibleClassChangError異常的子類, 如 java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError等。
準備
主要是為類變量(注意,不是實例變量)分配內存,并且賦予初值,此時的賦值是Java虛擬機根據不同變量類型的默認初始值:
如8種基本類型的初值,默認為0;引用類型的初值則為null;常量的初值即為代碼中設置的值
1、final static temp = 100,此時temp就是賦值 100。
2、String temp = “123456”,此時temp值就是null。
3、int temp = 100,此時temp值就是0。
解析
將類的二進制數據中的符號引用替換成直接引用(符號引用是用一組符號描述所引用的目標;直接引用是指向目標的指針)
可以認為是一些靜態綁定的會被解析,動態綁定則只會在運行時進行解析;靜態綁定包括一些final方法(不可以重寫),static方法(只會屬于當前類),構造器(不會被重寫)
在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換為具體的內存地址或偏移量,也就是直接引用。
初始化
初始化,則是為標記為常量值的字段賦值的過程。
換句話說,只對static修飾的變量或語句塊進行初始化。
如果初始化一個類的時候,其父類尚未初始化,則優先初始化其父類。
如果同時包含多個靜態變量和靜態代碼塊,則按照自上而下的順序依次執行。
涉及問題
一個類的構造器,代碼塊,靜態代碼塊,成員變量的 的執行順序。
//父類
//子類
執行結果:
我是父靜態成員變量p2
我是父靜態代碼塊1
我是父靜態代碼塊2
我是子靜態成員變量c2
我是子靜態代碼塊1
我是子靜態代碼塊2
我是父成員變量p1
我是父代碼塊1
我是父代碼塊2
我是父構造器
我是子成員變量c1
我是子代碼塊1
我是子代碼塊2
我是子構造器
總結
以上是生活随笔為你收集整理的java类加载过程_面试官:java类的加载过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java反射机制_java反射机制的讲解
- 下一篇: qq模板图片asqq_重要更新 电脑编辑