物件例項化

2022-09-19 05:48:09 字數 2722 閱讀 3693

參考資料:尚矽谷jvm教程

面試題

美團:

物件在jvm中是怎麼儲存的?

物件頭資訊裡面有哪些東西?

螞蟻金服:

j**a物件頭有什麼?

8.1.1 建立物件的方式

8.1.2. 建立物件的步驟

public class objecttest 

}

前面所述是從位元組碼角度看待物件的建立過程,現在從執行步驟的角度來分析:

1. 判斷物件對應的類是否載入、鏈結、初始化

虛擬機器遇到一條new指令,首先去檢查這個指令的引數能否在metaspace的常量池中定位到乙個類的符號引用,並且檢查這個符號引用代表的類是否已經被載入,解析和初始化(即判斷類元資訊是否存在)。

如果沒有,那麼在雙親委派模式下,使用當前類載入器以classloader + 包名 + 類名為key進行查詢對應的 .class檔案;

2. 為物件分配記憶體

首先計算物件占用空間的大小,接著在堆中劃分一塊記憶體給新物件。如果例項成員變數是引用變數,僅分配引用變數空間即可,即4個位元組大小

如果記憶體規整:虛擬機器將採用的是指標碰撞法(bump the point)來為物件分配記憶體。

如果記憶體不規整:虛擬機器需要維護乙個空閒列表(free list)來為物件分配記憶體。

選擇哪種分配方式由j**a堆是否規整所決定,而j**a堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。

3. 處理併發問題

4. 初始化分配到的記憶體

所有屬性設定預設值,保證物件例項欄位在不賦值時可以直接使用

5. 設定物件的物件頭

將物件的所屬類(即類的元資料資訊)、物件的hashcode和物件的gc資訊、鎖資訊等資料儲存在物件的物件頭中。這個過程的具體設定方式取決於jvm實現。

6. 執行init方法進行初始化

在j**a程式的視角看來,初始化才正式開始。初始化成員變數,執行例項化**塊,呼叫類的構造方法,並把堆內物件的首位址賦值給引用變數

因此一般來說(由位元組碼中跟隨invokespecial指令所決定),new指令之後會接著就是執行方法,把物件按照程式設計師的意願進行初始化,這樣乙個真正可用的物件才算完成建立出來。

給物件屬性賦值的操作

物件例項化的過程

載入類元資訊

為物件分配記憶體

處理併發問題

屬性的預設初始化(零值初始化)

設定物件頭資訊

屬性的顯示初始化、**塊中初始化、構造器中初始化

8.2.1. 物件頭(header)

物件頭包含了兩部分,分別是執行時元資料(mark word)和型別指標。如果是陣列,還需要記錄陣列的長度

執行時元資料

型別指標

指向類元資料instanceklass,確定該物件所屬的型別。

8.2.2. 例項資料(instance data)

它是物件真正儲存的有效資訊,包括程式**中定義的各種型別的字段(包括從父類繼承下來的和本身擁有的字段)

8.2.3. 對齊填充(padding)

不是必須的,也沒有特別的含義,僅僅起到佔位符的作用

小結

jvm是如何通過棧幀中的物件引用訪問到其內部的物件例項呢?

8.3.1. 控制代碼訪問

reference中儲存穩定控制代碼位址,物件被移動(垃圾收集時移動物件很普遍)時只會改變控制代碼中例項資料指標即可,reference本身不需要被修改

8.3.2. 直接指標(hotspot採用)

直接指標是區域性變數表中的引用,直接指向堆中的例項,在物件例項中有型別指標,指向的是方法區中的物件型別資料

reflect例項化物件

1.在使用class例項化物件的時候,必須保證類中存在乙個無參構造器,否則無法使用。2.如果想要使用有參構造器進行物件的例項化操作,則必須使用constructor類完成,此類表示構造方法,並通過可變引數傳遞要求的內容。如果想要呼叫有參,則必須按照以下的步驟 1 通過class類中的getconst...

String例項化物件

string類為引用資料型別,其實例化方式分為兩類 1.直接賦值。2.使用構造方法例項化物件。1.直接賦值其基本語法為 public class jiestring 2.使用構造方法例項化物件其基本語法為 public class jiestring 但其兩種例項化方式有不同之處,直接賦值法中其值是...

JVM物件例項化

new 最常見的方法 的靜態方法 builder factory的靜態方法 class 的 newinstance 8中能用,9已經標註過時了,反射的方式,只能呼叫空參的構造器,許可權必須是public。constructor 的 newinstance 反射的方式,可以呼叫空參,帶參,取代了第二個...