天天看點

類的初始化——生命周期

加載

(1.生成類對象)

通過一個類的全限定名來擷取定義此類的二進制位元組流。

将這個位元組流所代表的類靜态存儲結構轉化為方法區的運作時資料結構。

在堆中生成一個代表這個類的 java.lang.Class 對象(這樣便可以通過該對象通路步驟2中方法區的那些資料結構)。

連接配接

(驗證)

總結一下:驗證階段是非常重要的,但不是必須的,它對程式運作期沒有影響,如果所引用的類經過反複驗證沒有問題,那麼可以考慮采用 -Xverify:none參數來關閉大部分的類驗證措施,以縮短虛拟機類加載的時間。

準備:

(靜态變量記憶體配置設定,方法區内初始化指派,static和final修飾的值(全局常量)放入常量池

1、這時候進行記憶體配置設定的僅包括類變量(static),而不包括執行個體變量,執行個體變量會在對象執行個體化時随着對象一塊配置設定在Java堆中。

2、這裡設定類變量的初始值是資料類型預設的零值

解析:

(1.常量池裡面的值都是符号引用(就是瞎寫,等到對象生成的時候再指向對象))

1.解析階段是虛拟機将常量池内的符号引用(JVM 并不知道引入的其他對象在哪裡,是以就用唯一符号來代替)轉化為直接引用(記憶體位址)的過程。

初始化

(執行代碼,執行static語句,和靜态變量的顯示指派)

初始化是類加載過程的最後一個步驟,直到這一階段虛拟機才真正開始執行類中編寫的代碼。

初始化就是執行一個class中的static語句和所有類變量的指派操作(對應位元組碼就是clinit方法)。

使用

(主動引用就是類加載時機;被動引用:除了下述5種場景,其他所有類的方式都不會觸發初始化,稱為被動引用。)

使用階段包括主動引用(初始化階段所做的事情就是主動引用)和被動引用,需要注意的是:被動引用不會引起類的初始化。

解除安裝

一個類什麼時候結束生命周期,取決于它的 Class 對象何時結束生命周期。需要注意的是:由 Java 虛拟機自帶的類加載器所加載的類,在虛拟機的生命周期中,始終不會被解除安裝。

是以類在使用階段完成後,如果滿足下面這些情況,就會被解除安裝掉:

  • 加載該類的類加載器已經被回收了
  • jvm 堆中不存在該類的任何執行個體了
  • 該類對應的 Class 對象沒有被引用了

總結:

(生成類對象)

(驗證)

(靜态變量記憶體配置設定,在方法區内初始化指派,static和final修飾的值(全局常量)放入常量池)

(常量池裡面的值都是符号引用(就是瞎寫,等到對象生成的時候再指向對象))

(執行代碼,執行static語句,和靜态變量的顯示指派)

(主動引用就是類加載時機;((new對象)(反射)(子類準備生成對象,父類就要開始初始化了,main方法(目前類進入類加載)-》(準備生成對象了,在用構造器之前先把非靜态的成員變量走一遍,最後構造器指派))

被動引用:除了下述5種場景,其他所有類的方式都不會觸發初始化,稱為被動引用。)

(人話:main方法觸發類加載,靜态的先走一遍(所有觸發了類加載的類都按順序走一遍靜态,先初始化再指派),靜态的走完了,執行main裡面的語句,開始走構造器,在構造器之前再把類的成員變量初始化和指派走完)之後等解除安裝

----------

主動引用

java類的初始化階段,虛拟機規範嚴格規定了5種情況必須立即對類進行初始化。

1.遇到new、getstatic、putstatic或invokestatic這4條位元組碼指令時,如果類沒有進行過初始化,則需要先觸發其初始化。(new對象)

2.使用java.lang.reflect包的方法對類進行反射調用的時候,如果類沒有進行過初始化,則需要先觸發其初始化。(反射)

3.當初始化一個類時,如果發現其父類沒有進行過初始化,則需要先觸發其父類的初始化。

(子類初始化之前父類一定先初始化)

4.當虛拟機啟動時,使用者需要制定一個要執行的主類(包含main()方法的那個類),虛拟機會先初始化這個類。

(main方法)

5.當使用JDK1.7的動态語言支援時,如果一個java.lang.invoke.MethodHandle執行個體最後的解析結果REF_geStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且這個方法句柄所對應的類沒有進行過初始化,則需要先觸發其初始化。