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

你说的很对,感谢你,顶着我的一片骂名道出真相。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值