什么是類加載器?
類加載器:JVM只會運行二進制文件,類加載器的作用就是將字節碼文件加載到JVM中,從而Java
程序能夠啟動起來。
類加載器有哪些?
啟動類加載器(BootStrap ClassLoader):加載JAVA HOME/jre/lib目錄下的庫
擴展類加載器(ExtClassLoader):主要加載JAVA HOME/jre/lib/ext目錄中的類
應用類加載器(AppClassLoader):用于加載classPath下的類。是默認的類加載器,一般來說,java
應用的類都是由該加載器加載的。
在java的日常應用開發中,類的加載基本上都是由這三種加載器互相配合完成加載的。
自定義類加載器(CustomizeClassLoader):自定義類繼承ClassLoader,實現自定義類加載規則。
什么是雙親委派模型?
加載某一個類,先委托上一級的加載器進行加載,如果上級加載器也有上級,則會繼續向上委托
如果該類委托上級沒有被加載,子加載器嘗試加載該類
舉例
在加載Student類時,應用類加載器會委派擴展類加載器,擴展類加載器會委派啟動類加載器,啟動類加載器不會加載,擴展類不會加載,然后應用類加載器加載Student類
JVM為什么會采用雙親委派機制?
(1)通過雙親委派機制可以避免某一個類被重復加載,當父類已經加載后則無需重復加載,保證唯
一性。
(2)為了安全,保證類庫API不會被修改
例子
類裝載的執行過程
?類從加載到虛擬機中開始,直到卸載為止,它的整個生命周期包括了:加載、驗證、準備、解析、初始化、使用和卸載這7個階段。其中,驗證、準備和解析這三個部分統稱為連接(linking)
加載階段:
- 通過類的全名,獲取類的二進制數據流。
- 解析類的二進制數據流為方法區內的數據結構(Java類模型)
- 創建java.lang.Class類的實例,表示該類型。作為方法區這個類的各種數據的訪問入口
驗證階段:驗證類是否符合JVM的規范,安全性檢查
準備階段:為類變量分配內存并設置類變量的初始值
- static變量,分配空間在準備階段完成(設置默認值),賦值在初始化階段完成
- static變量是final的基本類型,以及字符串常量,值已確定,賦值在準備階段完成
- static變量是final的引用類型,那么賦值也會在初始化階段完成
例子?
變量b分配空間在準備階段完成(設置默認值0),賦值在初始化階段完成 b=10
變量c 和 變量d?值已確定,賦值在準備階段完成
變量obj?賦值也會在初始化階段完成
解析階段:把類中的符號引用轉換為直接引用
符號引用和直接引用的例子
比如:方法中調用了其他方法,方法名可以理解為符號引用,而直接引用就是使用指針直接指向方法
初始化階段:對類的靜態變量,靜態代碼塊執行初始化操作
- 如果初始化一個類的時候,其父類尚未初始化,則優先初始化其父類
- 如果同時包含多個靜態變量和靜態代碼塊,則按照自上而下的順序依次執行。
案例:
public class Application {public static void main(String[] args) {// 1. 首次訪問這個類的靜態變量或靜態方法時System.out.println(Animal.num);// 2. 子類初始化,如果父類還沒初始化,會引發父類先初始化System.out.println(Cat.sex);// 3. 子類訪問父類靜態變量,只觸發父類初始化System.out.println(Cat.num);}
}class Animal {static int num = 55;static {System.out.println("Animal 靜態代碼塊...");}
}class Cat extends Animal {static boolean sex = false;static {System.out.println("Cat 靜態代碼塊...1");}static {System.out.println("Cat 靜態代碼塊...2");}
}
1.訪問父類的變量
執行結果
2.訪問子類的變量
3.子類訪問父類的靜態變量
使用階段:
- JVM 開始從入口方法開始執行用戶的程序代碼
- 調用靜態類成員信息(比如:靜態字段、靜態方法)
- 使用new關鍵字為其創建對象實例
卸載階段:當用戶程序執行完畢之后,JVM便開始銷毀創建的Class對象
總結:
加載:查找和導入class文件
驗證:保證加載類的準確性
準備:為類變量分配內存并設置類變量初始值
解析:把類中的符號引用轉換為直接引用
初始化:對類的靜態變量,靜態代碼塊執行初始化操作
使用:JVM 開始從入口方法開始執行用戶的程序代碼
卸載:當用戶程序代碼執行完畢后,JM便開始銷毀創建的Class對象。
?