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");
}
}
执行结果:并没有输出" 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
};
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);
}
}
输出结果(并没有输出 “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
)
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();
}
}
}
输出结果:
我当时为什么会写这篇blog?
这可能需要,讨论到另外一个知识点:《静态代码块是在主线程中执行吗?》
因为这个特性,android 5.0 之前的版本,提供的 AsyncTask 类 ,为我们android开发者留下了一个坑。
之后的版本修复了这个坑。
我不想展开来细说这个问题,因为:
1. 这个问题与这篇blog的标题不符
2. 不想把这篇blog的篇幅拉的很长,尽管已经很长了
3. 并不知道大家对这个问题是否有兴趣,如果大家对这个问题有兴趣的话,给我留言,我看到有留言,我再来开一篇新的blog,专门来说清楚这个问题。
最后 4楼:@gate120
你说的很对,感谢你,顶着我的一片骂名道出真相。