下面簡單總結(jié)一下對象的創(chuàng)建及其內(nèi)存分布(以下只討論普通Java對象,不包括數(shù)組和Class對象)
知識結(jié)構(gòu)
1.了解對象的內(nèi)存分布
- 對象內(nèi)存分配在堆中(絕大部分普通Java對象,像Class對象是分配在方法區(qū)中的)
- 對象開始的部分是對象頭,包括兩部分信息
- 第一部分是自身運行時數(shù)據(jù),存放了跟對象有關(guān)的信息,如哈希碼、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時間戳等
- 第二部分是類型指針,即對象指向它的類元數(shù)據(jù)的指針??梢酝ㄟ^它知道該對象是哪個類的實例
- 中間是實例數(shù)據(jù),就是在程序代碼中定義的各種類型的字段內(nèi)容。包括從父類繼承下來的。執(zhí)行<init>的時候也要執(zhí)行父類的初始化
- 最后是對齊填充,沒有特殊含義,就是為了讓對象大小為8的整數(shù)倍
2.實例化前先找類,相當(dāng)于“模板” (檢查該類是否被加載過)
當(dāng)虛擬機遇到一條new指令時,首先將去檢查這個指令的參數(shù)是否能在常量池中定位到一個類的符號引用(注:這個的作用是檢查你想實例化的類是否真的存在,具體怎么檢查可以自己去了解一下類文件結(jié)構(gòu)中常量池部分,簡單來說就是編譯期的時候執(zhí)行new指令的這個類在編譯成Class文件的時候,它的常量池已經(jīng)存放了想實例化的類名了),然后再檢查這個類是否已經(jīng)被加載、解析、初始化過了。若沒有則先進行類加載。
3.有了類,就把類實例化,就是對象的創(chuàng)建
- 分配內(nèi)存,先在堆中開辟空間,對象大小在類加載完之后可完全確定。
- 內(nèi)存分配完之后,把空間都初始化為零值。
- 設(shè)置對象頭,對象頭存放了關(guān)于這個對象的信息。
- 初始化,根據(jù)代碼,執(zhí)行<init>方法,給字段賦值