JAVA靜態代碼塊會在類被加載時自動執行?
很多Java開發者的思想,被這個思想深深的輪姦了n遍,傳播這個錯誤思想的博客,在網上一堆,越來越多的人被輪姦。
如:http://blog.csdn.net/leeyu35/article/details/7755304
那麼我們程序來證明這句話是錯誤的:
- class MyClass1 {
- static {//靜態塊
- System.out.println("static block ");
- }
- }
- public class Main {
- Class[] classArray = {
- MyClass1.class//這樣引用該類,必然需要將該類加載到虛擬機中
- };
- public static void main(String[] args){
- System.out.println("hello word");
- }
- }
class MyClass1 {
static {//靜態塊
System.out.println("static block ");
}
}
public class Main {
Class[] classArray = {
MyClass1.class//這樣引用該類,必然需要將該類加載到虛擬機中
};
public static void main(String[] args){
System.out.println("hello word");
}
}
執行結果:並沒有輸出" static bolck"
那麼什麼時候纔會調用靜態塊呢?我找到一篇,介紹比較詳細的博客。
http://www.cnblogs.com/ivanfu/archive/2012/02/12/2347817.html
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 以上發表於2014-10-16 20:13 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 以下更新於:2017-07-24 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
關於 《Java誤區: 靜態代碼塊,會在類被加載時自動執行?》 回覆與更新
1.道歉:
首先,我承認,上面的demo犯了一個嚴重的低級的錯誤,Main的成員classArray並不會被賦值,因爲系統並不會創建Main的對象。正確的寫法應該是:
- static Class[] classArray = {
- MyClass1.class
- };
static Class[] classArray = {
MyClass1.class
};
2. 謝謝你們友善的提醒。
5樓:@Johnny_Xiu , 7樓:@jzb2008lds ,10樓:@深藍水域 , 12樓:@asd1_123
你們的回覆:“請刪除本文,以防誤導他人”。我看到了,很抱歉很久沒有上csdn,這麼晚纔看到。
恩,謝謝你們友善的提醒。
但是,尼采說過:"生活不能逃避,只能勇敢面對"。
所以我不打算刪帖逃避問題,那是懦夫纔會做的事,我選擇把問題解決。
demo和blog是2014-10-16寫的;已經過去了3年,我也不記得當時爲什麼會犯這麼一個錯誤,也許是粗心,也許是因爲喝了點酒,誰知道呢……
但是,這篇blog要表達的觀點一定是對的。
3.爲了減少歧義,改進後的demo
- package com.test;
- import java.lang.Class;
- class MyClass1 {
- static {//靜態塊
- System.out.println("static block ");
- }
- }
- public class Hello {
- public static void main(String[] args){
- System.out.println("hello word: " + MyClass1.class);
- }
- }
package com.test;
import java.lang.Class;
class MyClass1 {
static {//靜態塊
System.out.println("static block ");
}
}
public class Hello {
public static void main(String[] args){
System.out.println("hello word: " + MyClass1.class);
}
}
輸出結果(並沒有輸出 “static block”。):
4. 爲什麼 “MyClass1.class” 這種方式,不會觸發,MyClass1的靜態代碼塊的執行?
如上圖所示,靜態代碼塊的執行是處在類加載的最後一個階段“初始化”。參考Oracle:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
那麼什麼時候會觸發初始化階段,請參考上述文檔中的:5.5. Initialization
英語不太好的,搓這裏 http://blog.csdn.net/xuefeng0707/article/details/9132339
根據上面文檔,顯然:MyClass1.class 這種使用方式,並不會觸發,MyClass1類的初始化。所以並不會執行,MyClass1的靜態代碼塊。
5.Class.forName()
- public static Class<?> forName(
- String name,
- //如果initialize = false,那麼類會被加載,但不會執行靜態代碼塊。
- boolean initialize,//whether the class must be initialized;
- ClassLoader loader
- )
public static Class<?> forName(
String name,
//如果initialize = false,那麼類會被加載,但不會執行靜態代碼塊。
boolean initialize,//whether the class must be initialized;
ClassLoader loader
)
http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String,%20boolean,%20java.lang.ClassLoader)
3樓:@UltraNeo
你可能沒有看到,當時blog末尾推薦的鏈接:
http://www.cnblogs.com/ivanfu/archive/2012/02/12/2347817.html
鏈接文中也講解了Class.forName()方法.
首先你是對的:Class.forName("com.test.MyClass1");這樣調用在加載過程會執行靜態代碼塊。
但是:不代表所有的forName()方法的調用都會執行“靜態代碼塊”。
如下並不會執行靜態代碼塊:
Class.forName("com.test.MyClass1",false,classLoader);
6. MyClass1.class的使用方式,會觸發 MyClass1.class 加載到虛擬機的嗎?
答案當然是肯定的:一定會加載到虛擬機。“並且他的Class對象存儲在ClassLoader中”
6樓:@爍GG
廢話不多說,demo證明一切:
- public class Main {
- public static void main(String[] args){
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- printClassesOfClassLoader(loader);
- System.out.println("-------------------- hello " + MyClass1.class + " --------------------");
- printClassesOfClassLoader(loader);
- }
- public static void printClassesOfClassLoader(ClassLoader loader){
- try {
- Field classesF = ClassLoader.class.getDeclaredField("classes");
- classesF.setAccessible(true);
- Vector<Class<?>> classes = (Vector<Class<?>>) classesF.get(loader);
- for(Class c : classes) {
- System.out.println(c);
- }
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
public class Main {
public static void main(String[] args){
ClassLoader loader = Thread.currentThread().getContextClassLoader();
printClassesOfClassLoader(loader);
System.out.println("-------------------- hello " + MyClass1.class + " --------------------");
printClassesOfClassLoader(loader);
}
public static void printClassesOfClassLoader(ClassLoader loader){
try {
Field classesF = ClassLoader.class.getDeclaredField("classes");
classesF.setAccessible(true);
Vector<Class<?>> classes = (Vector<Class<?>>) classesF.get(loader);
for(Class c : classes) {
System.out.println(c);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
輸出結果:
我當時爲什麼會寫這篇blog?
這可能需要,討論到另外一個知識點:《靜態代碼塊是在主線程中執行嗎?》
因爲這個特性,android 5.0 之前的版本,提供的 AsyncTask 類 ,爲我們android開發者留下了一個坑。
之後的版本修復了這個坑。
我不想展開來細說這個問題,因爲:
1. 這個問題與這篇blog的標題不符
2. 不想把這篇blog的篇幅拉的很長,儘管已經很長了
3. 並不知道大家對這個問題是否有興趣,如果大家對這個問題有興趣的話,給我留言,我看到有留言,我再來開一篇新的blog,專門來說清楚這個問題。
最後 4樓:@gate120
你說的很對,感謝你,頂着我的一片罵名道出真相。