Class.forName雜談

既然是雜談,那麼確定會比較雜亂,都是點到爲止,不回作過多的原理分析,若是對於原理,可能須要深刻了解JVM內部的東西了。<br/> 首先,我來展現一下幾個現象,而後對這幾個現象進行分析。<br/> 相關幾個類的定義java

<!-- lang:java-->
package com.bieber.gc;

public class Super {

static{
	System.out.println("super static block");
}
public Super(){
	System.out.println("super init");
}

public void test(){
	System.out.println("invoke test");
}
}

public class Main extends Super{

 
public Main() {
	System.out.println("main init");
}

static{
 System.out.println("sub static block");
}
public void test(){
	System.out.println("main test");
}

}

這裏涉及到兩個類,下面針對這兩個類來寫幾個測試用例。<br/> ####用例一函數

用例代碼

<!-- lang:java-->
public static void main(String[] args) throws Exception {
	try {
		System.out.println("#########start load class##########");
		 Thread.currentThread().getContextClassLoader().loadClass("com.bieber.gc.Main");
		System.out.println();
		System.out.println("#########start init class#########");
		Main main = new Main();
		System.out.println();
		System.out.println("#########invoke#########");
		main.test();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}

#####輸出結果測試

<!-- lang:java -->
#########start load class##########

#########start init class#########
super static block
sub static block
super init
main init

#########invoke#########
main test

#####結果分析 能夠看到經過Classloader加載類的時候,並無執行static代碼塊,而static代碼塊卻放到了調用構造函數的時候執行了,而且static代碼塊是在構造函數以前執行的。同時在調用在子類重寫的方法時候,父類方法沒有執行(這點是毫無疑問的)。 ####用例二 #####用例代碼code

<!-- lang:java -->
public static void main(String[] args) throws Exception {
	try {
		System.out.println("#########start load class##########");
		Class.forName("com.bieber.gc.Main", true, Thread.currentThread().getContextClassLoader());
		System.out.println();
		System.out.println("#########start init class#########");
		Main main = new Main();
		System.out.println();
		System.out.println("#########invoke#########");
		main.test();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}

#####執行結果內存

<!-- lang:java -->
#########start load class##########
super static block
sub static block

#########start init class#########
super init
main init

#########invoke#########
main test

#####結果分析 發現這個時候子類和父類的static代碼塊在調用構造函數以前執行的,這點說明此處的Class.forNameClassLoader執行效果同樣。其餘部分和上面基本一致。 ####用例三 #####用例代碼ssl

<!-- lang:java -->
public static void main(String[] args) throws Exception {
	try {
		System.out.println("#########start load class##########");
		Class.forName("com.bieber.gc.Main", false, Thread.currentThread().getContextClassLoader());
		System.out.println();
		System.out.println("#########start init class#########");
		Main main = new Main();
		System.out.println();
		System.out.println("#########invoke#########");
		main.test();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}

#####執行結果開發

<!-- lang:java -->
#########start load class##########

#########start init class#########
super static block
sub static block
super init
main init

#########invoke#########
main test

#####結果分析 這個執行結果和和用例一的結果同樣。get

####總結 上面列舉了三個測試用例,用例二和用例三的卻別就是 Class.forName("com.bieber.gc.Main", true, Thread.currentThread().getContextClassLoader());Class.forName("com.bieber.gc.Main", false, Thread.currentThread().getContextClassLoader());的區別,這個很容易理解,其實第一個是在加載類的時候是初始化了類(Class)的其餘信息,而第二個是延遲初始化。若是是延遲初始化從執行結果上來看和hread.currentThread().getContextClassLoader().loadClass("com.bieber.gc.Main");是同樣的。<br/> 經過上面能夠理解爲,類的加載分爲兩個步驟:<br/>it

  1. 只是裝載類,相似將類的字節碼加載到JVM中<br/>
  2. 解析類的結構,並初始化類的相關信息,好比static代碼塊<br/>

而且能夠獲得父類的加載老是在子類以前,無論是static代碼執行,仍是構造函數的調用。這也很容易理解,由於子類中可能會調用父類的信息,因此先須要將父類準備好了,子類調用的時候,纔沒問題。<br/>io

此處給一個建議:謹慎在父類中定義protected(public) static的屬性,由於這個時候,是全部子類共用一分內存,很容致使讀寫衝突。<br/>

針對上面的測試,下面列舉出幾個其餘的測試,你們看看會獲得什麼結果?

<!-- lang:java -->
package com.bieber.gc;

public class Field {

static{
	System.out.println("field static block");
}
}

public class Main extends Super{


private static Field field=new Field();
public Main() {
	System.out.println("main init");
}

static{
 System.out.println("sub static block");
}
public void test(){
	System.out.println("main test");
}

}

或者

public class Main extends Super{


private static Field field;
public Main() {
	System.out.println("main init");
}

static{
 System.out.println("sub static block");
}
public void test(){
	System.out.println("main test");
}

}

我把Main類作了上面的調整,看看執行上面的測試用例,會獲得什麼結果。歡迎討論交流,也但願你們也能分享一下大家在開發過程當中的一些東西。

相關文章
相關標籤/搜索