【JVM】JVM之類加載器


一、前言

  首先,小小測試,看是否已經掌握了JVM類加載的過程

  1.1、測試一

class Singleton {
	private static Singleton sin = new Singleton();
	public static int counter1;
	public static int counter2 = 0;
	
	private Singleton() {
		counter1++;
		counter2++;
	}
	
	public static Singleton getInstance() {
		return sin;
	}
}

public class Test {
	public static void main(String[] args) {
		Singleton sin = Singleton.getInstance();
		System.out.println(sin.counter1);
		System.out.println(sin.counter2);
	}
}	

  輸出結果為:

  1 3 ?

  1 0 ?  

  0 1?

  1.2、測試二:

class Singleton {	
	public static int counter1;
	public static int counter2 = 2;
	private static Singleton sin = new Singleton();

	private Singleton() {
		counter1++;
		counter2++;
	}
	
	public static Singleton getInstance() {
		return sin;
	}
}

public class Test {
	public static void main(String[] args) {
		Singleton sin = Singleton.getInstance();
		System.out.println(sin.counter1);
		System.out.println(sin.counter2);
	}
}	

  

輸出結果為:

  1 3 ?

  1 2 ?  

  0 1?

正確的輸出結果如下:

測試一的結果為:1 0

測試二的結果為:1 3

如果對結果有疑惑或者不知道原因的園友需要了解類加載器的具體細節,相信看了本篇文章,一定會解開您的疑惑。廢話不多說,直奔主題。

二、背景知識

  2.1、Java虛擬機通過裝(加)載、連接、初始化一個Java類型,使該類型可以被正在運行的Java程序所使用。  

  ①裝(加)載類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區中,然后在堆區創建一個java.lang.Class對象,用來封裝類在方法區內的數據結構,之后可以用Class對象進行相關的反射操作。

  ②連接分為三個子步驟     

    驗證:確保被加載的類的正確性

    准備:為類的靜態變量分配內存,並將其初始化為默認值

    解析: 把類中的符號引用轉換為直接引用

  ③初始化為為類的靜態變量賦予正確的初始值

  如下為流程圖:

  2.2、關於初始化的細節  

  所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才初始化他們,下面六種情況符合首次主動使用要求。    

    ① 創建類的實例    

    ②訪問某個類或接口的非常量靜態域,或者對該非常量靜態域賦值

    ③ 調用類的靜態方法

    ④反射(如Class.forName(“com.test.Test”)(其中Test為一個類),而Test.class就不是首次使用)

    ⑤初始化一個類的子類

    ⑥Java虛擬機啟動時被標明為啟動類的類(Test)(Test為包含了程序入口main方法的類)

  2.3、如論如何,如果一個類型在其首次主動使用之前還沒有被裝(加)載和連接的話,那它必須在此時進行加載和連接,這樣它才能夠被初始化。

三、問題分析

  3.1、讀到這里應該可以分析出為什么之前的程序會輸出那樣的結果,下面我們來一起分析一下整個過程。

  ①對於測試一的結果分析

  首先在main中調用了Singleton的getInstance類靜態方法,符合第③條,需要初始化類,即初始化Singleton,首先需要裝(加)載和連接,從硬盤中加載進內存,然后進入連接的驗證,沒有問題,OK,進入准備階段,此時,將類變量sin、counter1、counter2分配內存,並初始化默認值null、0、0。緊接着,將符號引用轉化為直接引用(暫  時不不要太了解,程序中就是將Singleton符號轉化為在內存里直接對地址的引用,這樣就可以通過地址直接訪問Singleton類型了)。接下來是初始化過程,首先調用sin的構造方法,然后將counter1、counter2分別+1,即counter1 = 1,counter2 = 1,完成了sin靜態變量的初始化,然后初始化靜態變量counter1,但是由於沒有對counter1賦初值,所以counter1還是為1,然而,程序中對counter2進行了賦初值操作,即將counter2賦值為0。這樣便完成了類型的初始化,得到的counter1和counter2的結果為1和0,分析完畢。

  結果分析流程圖如下:

    

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 ②同理也可以對測試二進行結果分析

四、總結

  整個類的初始化三個階段細節過程遠比這個復雜得多,但是我們仍可以通過類的整個宏觀流程來分析出正確的結果,對過程的分析也有助於我們寫出正確的程序。真正做到知其然知其所以然。也感謝各位園友的觀看,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM