Java類定義
Class文件是一組以8位字節爲基礎的二進制流,各個數據之間緊湊判斷
Class文件是一種類似於C語言結構體的僞結構存儲數據,僞結構只有兩種數據類型:無符號數和表
Class文件本質是一張數據表
class文件格式如圖
類加載
類加載生命週期:
觸發類初始化的幾種方式(有且僅有):
- new,getstatic,putstatic 或 invokestatic字節指令時(注意用子類引用父類static變量,不同虛擬機可能稍有差異,這個具體看虛擬機配置,有的會觸發子類加載,有的不會)
- 使用使用反射對類進行調用
- 當子類初始化,發現父類未初始化觸發父類初始化
- 當虛擬機啓動,指定的執行主類(即包含main方法的那個類)
- MethodHandle動態代理觸發類加載
加載(loading):
1. 通過一個類的全限定名來獲取定義此類的二進制字節流
2. 將這個字節流所代表的靜態存儲結構轉化爲方法區的運行時數據結構
3. 在Java堆中生產一個代表這個類的java.lang.Class對象,作爲方法區這些數據的訪問入口
校驗(Verfication):
1. 文件格式的驗證
2. 元數據驗證
3. 字節碼驗證
4. 符號引用驗證
準備(Preparation):正式爲類變量分配內存並設置初始值
解析(Resolution):是將常量池內符號引用轉爲直接引用(變量引用在他自己及父類中遞歸搜索,匹配到就返回)
初始化(Initialization):初始化階段是執行類構造器()方法
Class加載(雙親委託模式):
主要類
- BootstrapClassLoder
- ExtensionClassLoader
- AppClassLoader
雙親委託加載關鍵代碼:
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//檢查請求的類是否已經加載過了
Class c = findLoadedClass(name);
if(c == null){
try {
ClassLoader parent = getParent();
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
}catch (ClassNotFoundException e){
//如果父類加載器異常拋出 ClassNotFoundException
//則說明父類無法完成加載
}
if(c==null){
//父類無法完成加載
//調用自己的findClass方法來進行加載
c = findClass(name);
}
}
if(resolve){
resolveClass(c);
}
return c;
}
注意:雖然我們可以在loadClass完成類加載,但是在JDK1.2以後,虛擬機推薦重寫findClass()方法,loadClass()方法的邏輯裏如果父類加載失敗,則調用自己的findClass()方法