在開發中,有時會遇到這樣的情況:我明明給乙個變數賦值了,為什麼在使用該變數時卻是沒有值的,這個和jvm的記憶體載入順序有關,當你使用該變數時,這個變數還沒初始化完成。
首先我們來看一段**:
public
class
objectloadmemorytest
extends
futest
@override
public
void
dodisplay()
public
static
void
main(string args)
}abstract class futest
public
abstract
void
dodisplay();
}
這段**的邏輯很簡單,就是在初始化子類物件的時候,呼叫這個類中的方法dodisplay,這個方法會列印該類中的所有的屬性,我們可以通過觀察列印結果來分析一下jvm在建立物件的時候,記憶體是如何載入的。
執行結果如下:
futest構造開始執行。。。。。
0100
null
100null
abcnull
null
objectloadmemorytest開始執行構造。。。。。。
100100
100100
abcabc
abc
我們發現在呼叫子類的建構函式的時候,會先呼叫父類的構造,在父類中我們同樣會列印所有的屬性,發現和子類中列印的結果是不一樣的。
通過列印結果,我們可以分析到以下幾點:
由此,我們可以推斷出如下結果:
類的載入過程:
1、啟動jvm,引導程式中需要使用的class檔案。
2、在載入class檔案的時候,所有的靜態內容(靜態成員變數,靜態成員函式,靜態**塊)都要載入到方法區的靜態區中。
3、當類中的所有靜態載入完成之後,開始給類中的所有靜態成員變數預設初始化。
4、類中的所有靜態成員變數預設初始化完成之後,開始給這些靜態成員變數顯示賦值。
5、所有靜態成員變數顯示賦值結束之後,開始執行類中的靜態**塊。
6、當所有的靜態**塊執行完成,代表當前這個class檔案才徹底被載入結束。
物件的建立過程:
1、使用new關鍵字建立物件,在堆給物件分配記憶體空間。
2、給物件所屬類中的所有非靜態成員變數分配空間並進行預設的初始化。
3、執行和new物件時傳遞引數一致的建構函式。
4、執行建構函式的的過程中有隱式的三步:
4.1、執行super() 語句,找父類的空引數建構函式
4.2、給非靜態成員變數進行顯示賦值。
4.3、執行構造**塊
4.4、建構函式中的自己寫的**執行。
5、建構函式執行完成,物件建立結束。
JVM載入機制
new 的過程到底做了什麼?首先jvm會進行載入,連線,初始化。在初始化前,類的資訊已經放在了方法區中並且static部分已經放入。在new的時候,才把obj放到堆中。並且這個時候,初始化屬性,初始化方法。for example class a private intmethod private s...
Jvm載入和Spring掃瞄的順序
jvm首先載入classes檔案裡面的類,然後載入jar中的,如果遇到同類的名的類,首先載入classes的.class,然後載入jar包裡面的,如果都在jar裡面,就無法保證載入順序。先是jvm載入在到classloader裡面,然後spring才能掃瞄到。lambda表示式一定是匿名內部類形式。...
JVM 類載入機制 類載入器
類宣告週期 檔案格式驗證 基於二進位製流,只有這一步是基於二進位製流,後續步驟都是基於方法區資料 1.魔數 cafe babe 開頭 2.主次版本是否在當前jvm支援範圍 3.常量池的常量是否不被支援 4.很多很多規範 元資料驗證 1.類是否有父類,object 2.匪類是否繼承了被final修飾的...