在日常開發和面試中,經常會被問到 “Java 中對象是如何被創建的?”
表面上只是一個 new
關鍵字,但 JVM 在幕后完成了一系列復雜操作。
可以總結為以下 六大步驟:
類加載檢查 → 分配內存 → 內存清零 → 設置對象頭 → 執行構造函數 → 引用賦值
一、類加載檢查
當第一次創建某個類的對象時,JVM 會先檢查這個類是否已經被加載:
如果未加載,則通過 類加載器(ClassLoader) 將
.class
文件讀入內存,并在方法區中生成對應的類信息。如果已加載,則直接進入下一步。
?這保證了類的元信息只會加載一次,所有對象實例共享同一份類描述信息。
二、分配內存
類信息已準備好后,JVM 會在 堆內存 中為新對象分配空間。
分配方式依賴于堆是否規整:
指針碰撞(Bump-the-pointer):堆內存連續,指針往后挪即可。
空閑列表(Free List):堆內存碎片化時,從空閑鏈表中找一塊合適的內存。
?這一步決定了對象的物理存儲位置。
三、內存清零
為了避免讀取到臟數據,JVM 會將新分配的內存空間全部清零:
數值型字段變為
0
布爾型字段變為
false
引用型字段變為
null
這是對象成員變量的默認初始化階段。
四、設置對象頭
JVM 會在新對象內存的起始位置寫入 對象頭 信息,包括:
Mark Word:保存哈希碼、GC 年齡、鎖狀態等運行時數據
Klass Pointer:指向類的元信息,表明該對象屬于哪個類
?這是對象和 JVM 交互的橋梁,GC 和鎖機制都依賴它。
五、執行構造函數
完成上述底層準備后,JVM 才會調用構造方法:
先執行父類構造函數,確保繼承鏈上的屬性都得到初始化
按照聲明順序給實例變量賦初始值
執行構造方法體中的邏輯
?這一步才是程序員在代碼中能感知到的初始化過程。
六、引用賦值
最后,新對象的引用會被返回,并賦值給棧幀中的局部變量表。
從這一刻開始,我們就可以通過引用來操作堆上的對象。