【Java 虚拟机原理】Java 类中的类加载初始化细节 ( 只使用类中的常量时加载类不会执行到 ‘初始化‘ 阶段 )
文章目錄
- 一、類加載初始化時機
- 二、常量加載示例
- 三、數(shù)組加載示例
一、類加載初始化時機
類加載時機 : Java 程序執(zhí)行時 , 并不是一開始將所有的字節(jié)碼文件都加載到內(nèi)存中 , 而是用到時才進行加載 ;
- 通過 new 關鍵字創(chuàng)建實例對象 ;
- 通過 Class 反射 獲取類 ; 如 : Class.forName(“Xxx”) 獲取類 ;
- 序列化 / 反序列化 ;
- 調(diào)用 clone 克隆對象 ;
- 有 main 函數(shù)的類 , 會默認自動加載 ;
- 調(diào)用子類 , 如果之前沒有加載過父類 , 則 自動加載父類 ;
- 訪問 類 的 靜態(tài)變量
有些類加載操作 , 不需要執(zhí)行 加載 -> 連接 ( 驗證 , 準備 , 解析 ) -> 初始化 這個完整的流程 ;
如 : 如果是 public final static 修飾的常量值 , 在編譯階段 , 就會將該值放到常量池中 ; 在類加載的過程中 , 只要執(zhí)行到 加載 -> 連接 ( 驗證 , 準備 , 解析 ) 階段 , 就可以完成常量池的初始化 , 即使沒有執(zhí)行 初始化 這個步驟 , 也不影響使用類中的常量值 ;
在 連接 的 準備 階段 , 為 普通 的 靜態(tài)變量 進行 默認賦值 , 但是針對 靜態(tài)常量 , 直接進行 指定賦值 ;
但是 普通的 靜態(tài)變量 的 指定賦值 , 是在 初始化 階段 完成的 ;
類 在 " 初始化 " 階段 , 調(diào)用 靜態(tài)代碼塊 ;
二、常量加載示例
類加載時 , 如果只用到了類中的常量 , 則只進行 " 加載 -> 連接 ( 驗證 , 準備 , 解析 ) " 兩個過程 :
public class Student {// 常量public static final int age = 18;static {// 加載類的 " 初始化 " 階段才執(zhí)行 靜態(tài)代碼塊// 如果只是進行了 " 連接 " , 沒有進行 初始化 , 則不會調(diào)用該代碼塊System.out.println("Student 靜態(tài)代碼塊調(diào)用");} }主函數(shù) :
public class Main {public static void main(String[] args) {int age = Student.age;System.out.println("main 函數(shù) age = " + age);} }執(zhí)行結(jié)果 :
上述 Student 類中的 靜態(tài)代碼塊 沒有被執(zhí)行 , 說明 類加載 的流程中 , " 初始化 " 步驟 , 沒有被執(zhí)行 ;
找到 Student.class 字節(jié)碼文件 , 然后使用
javap -v -Student.class查看該字節(jié)碼文件的附加信息 ;
在 " 常量表 " 中 , 發(fā)現(xiàn)了常量值 181818 , 這個常量值是在編譯階段就編譯到了字節(jié)碼中 ; 在 " 連接 " 的 " 準備 " 階段 , 該常量值就設置完畢 ; 出于最大限度性能優(yōu)化的考慮 , 如果不使用該類的其它值 , 就不會執(zhí)行 " 初始化 " 階段 ; 因此這里不會調(diào)用 靜態(tài)代碼塊 中的代碼 ;
Constant pool:#10 = Integer 18三、數(shù)組加載示例
對數(shù)組進行創(chuàng)建操作 , 如創(chuàng)建了一個對象數(shù)組 , 此時不會加載該對象對應的類 , 只會為其在內(nèi)存分配空間 ;
創(chuàng)建數(shù)組時 , 觸發(fā)的是 Student[] 數(shù)組類型的 類加載初始化 , 但是不會觸發(fā) Student 類的初始化操作 ;
如果調(diào)用數(shù)組中的元素時 , 就需要初始化 Student 類 ;
Student 類 :
public class Student {// 常量public static final int age = 18;static {// 加載類的 " 初始化 " 階段才執(zhí)行 靜態(tài)代碼塊// 如果只是進行了 " 連接 " , 沒有進行 初始化 , 則不會調(diào)用該代碼塊System.out.println("Student 靜態(tài)代碼塊調(diào)用");} }main 函數(shù) :
public class Main {public static void main(String[] args) {System.out.println("main 函數(shù)執(zhí)行");Student[] students = new Student[2];} }執(zhí)行結(jié)果 : 只是創(chuàng)建數(shù)組 , 只需要為其分配內(nèi)存空間 , 不需要為每個 Student 數(shù)組元素賦值 , 這里不需要初始化 Student 類 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 虚拟机原理】Java 类中的类加载初始化细节 ( 只使用类中的常量时加载类不会执行到 ‘初始化‘ 阶段 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 虚拟机原理】Android
- 下一篇: 【Java 泛型】泛型简介 ( 泛型类