JAVA靜態代碼塊會在類被加載時自動執行?

JAVA靜態代碼塊會在類被加載時自動執行?

        很多Java開發者的思想,被這個思想深深的輪姦了n遍,傳播這個錯誤思想的博客,在網上一堆,越來越多的人被輪姦。

        如:http://blog.csdn.net/leeyu35/article/details/7755304


那麼我們程序來證明這句話是錯誤的:

  1. class MyClass1 {  
  2.     static {//靜態塊  
  3.         System.out.println("static block ");  
  4.     }  
  5. }  
  6. public class Main {  
  7.   
  8.     Class[] classArray = {  
  9.             MyClass1.class//這樣引用該類,必然需要將該類加載到虛擬機中  
  10.     };  
  11.     public static void main(String[] args){  
  12.         System.out.println("hello word");  
  13.     }  
  14.   
  15. }  
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的對象。正確的寫法應該是:

  1. static Class[] classArray = {  
  2.         MyClass1.class  
  3. };    
    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

  1. package com.test;  
  2. import java.lang.Class;  
  3.   
  4. class MyClass1 {    
  5.     static {//靜態塊    
  6.         System.out.println("static block ");    
  7.     }    
  8. }  
  9. public class Hello {  
  10.     public static void main(String[] args){    
  11.         System.out.println("hello word: " + MyClass1.class);  
  12.     }    
  13. }  
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”。)

Alt 輸出結果


4. 爲什麼 “MyClass1.class” 這種方式,不會觸發,MyClass1的靜態代碼塊的執行?

Alt 類加載的5個階段

如上圖所示,靜態代碼塊的執行是處在類加載的最後一個階段“初始化”。參考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()

  1. public static Class<?> forName(  
  2.     String name,  
  3.     //如果initialize = false,那麼類會被加載,但不會執行靜態代碼塊。  
  4.     boolean initialize,//whether the class must be initialized;  
  5.     ClassLoader loader  
  6. )  
    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證明一切:

  1. public class Main {  
  2.   
  3.     public static void main(String[] args){  
  4.         ClassLoader loader = Thread.currentThread().getContextClassLoader();  
  5.         printClassesOfClassLoader(loader);  
  6.         System.out.println("-------------------- hello " + MyClass1.class + " --------------------");  
  7.         printClassesOfClassLoader(loader);  
  8.   
  9.     }  
  10.       
  11.     public static void printClassesOfClassLoader(ClassLoader loader){  
  12.         try {  
  13.             Field classesF = ClassLoader.class.getDeclaredField("classes");  
  14.             classesF.setAccessible(true);  
  15.             Vector<Class<?>> classes = (Vector<Class<?>>) classesF.get(loader);  
  16.             for(Class c : classes) {  
  17.                 System.out.println(c);  
  18.             }  
  19.         } catch (NoSuchFieldException e) {  
  20.             e.printStackTrace();  
  21.         } catch (IllegalAccessException e) {  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  
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();
        }
    }
}


輸出結果:

Alt 輸出結果



我當時爲什麼會寫這篇blog?

這可能需要,討論到另外一個知識點:《靜態代碼塊是在主線程中執行嗎?》
因爲這個特性,android 5.0 之前的版本,提供的 AsyncTask 類 ,爲我們android開發者留下了一個坑。
之後的版本修復了這個坑。

我不想展開來細說這個問題,因爲:
  1. 這個問題與這篇blog的標題不符
  2. 不想把這篇blog的篇幅拉的很長,儘管已經很長了
  3. 並不知道大家對這個問題是否有興趣,如果大家對這個問題有興趣的話,給我留言,我看到有留言,我再來開一篇新的blog,專門來說清楚這個問題。



最後 4樓:@gate120

你說的很對,感謝你,頂着我的一片罵名道出真相。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章