论坛首页 Java版

static块到底什么时候执行?

浏览 21633 次
该帖已经被评为精华帖
作者 正文
时间:2005-02-26
"java深度历险"一书在讲解“类装载”的一章中,举了以下的例子:
引用

[code:1]public interface Assembly{
public void start();
}

public class Word implements Assembly{
static{
System.out.println("Word static initialization!");
}

public void start(){
System.out.prinlnt("Word starts");
}
}

public class Office{
public static void main(String args[]) throws Exception{
Office off = new Office();
System.out.println("类别准备载入");
Class c = Class.forName(args[0],true,off.getClass().getClassLoader());
System.out.println("类别准备实例化");
Object o = c.newInstance();
Object o2= c.newInstance();
}
}[/code:1]执行java Office Word,运行结果如下:
“Loaded Office”
“类别准备载入”
“Loaded Accembly”
“Loaded Word””
“Word static initialization”
“类别准备实体化”。


但是如果将Office.java中Class.forName(args[0],true,off.getClass().getClassLoader())中的true变为false,再执行java Office Word结果显示为:
“Loaded Office”
“类别准备载入”
“Loaded Accembly”
“Loaded Word””
“类别准备实体化”
“Word static initialization”。


显然两次红字部分顺序相反,及static块执行的顺序不同。此书作者提出了原因,原文:
引用
“过去很多java书上提到静态初始化(static initializion block)时,都会说静态初始化区块只是在类第一次载入的时候才会被调用仅仅一次。可是上面输出却发现即使类被载入了,其静态初始化区块也没有被调用,而是在第一次调用newInstance方法时,静态初始化块才被真正调用,应该改成-静态初始化块只是在类被第一次实体化的时候才会被仅仅调用一次。”


其实,该书作者的上述描述有误。通过一个试验,就可以看出谬误所在。
[code:1]public class TestA{
static{
System.out.println("Static block executed!");
}
}

public class Test{
public static void main(String args[]){
Test test = new Test();
Class.forName("TestA",true,test.getClass().getClassLoader());
}
}[/code:1]运行一下,相信大家一定可以看到,“Static block executed!”的输出。这与
引用
而是在第一次调用newInstance方法时,静态初始化块才被真正调用
的说法矛盾。

其实我想事实是这样的:
一个类的运行,JVM做会以下几件事情 1、类装载 2、链接 3、初始化 4、实例化;而初始化阶段做的事情是初始化静态变量和执行静态方法等的工作。所以,当Class.forName(args[0],true,off.getClass().getClassLoader());中的true变为false的时候,就是告诉JVM不需再load class之后进行initial的工作。这样,将initial的工作推迟到了newInstance的时候进行。所以,static块的绝对不是什么“只是在类被第一次实体化的时候才会被仅仅调用一次”,而应该是在类被初始化的时候,仅仅调用一次。
   
时间:2005-02-28
呵呵,楼主研究颇深嘛,这么小的细节都看出来了,不错哦!
今天相信不少朋友又学到了新东东
   
0 请登录后投票
时间:2005-02-28
想也应该想到,如果是第一实例化才调用,那么JDBC Driver就没法加载了,JDBC Driver的加载就是利用了这个原理在静态块中向DriverManager注册自己的.
   
0 请登录后投票
时间:2005-02-28
凤舞凰扬 写道
呵呵,楼主研究颇深嘛,这么小的细节都看出来了,不错哦!
今天相信不少朋友又学到了新东东


曾经被“深度历险”一书的那段阐述误导过,后来发觉不是那么回事。
   
0 请登录后投票
时间:2005-02-28
的确我们是有机会在classLoad时候决定是否初始化static块...

:) 这点也应该算是比较基础的了.
   
0 请登录后投票
时间:2005-03-01
Tao 写道
想也应该想到,如果是第一实例化才调用,那么JDBC Driver就没法加载了,JDBC Driver的加载就是利用了这个原理在静态块中向DriverManager注册自己的.

这种classload机制还是蛮好的,在很多场合都可以加以使用。
   
0 请登录后投票
时间:2005-03-02
Tao 写道
想也应该想到,如果是第一实例化才调用,那么JDBC Driver就没法加载了,JDBC Driver的加载就是利用了这个原理在静态块中向DriverManager注册自己的.

所以说本来用Class.forName(.....)就可以的,但很多人还是喜欢用Class.forName(...).newInstance().
   
0 请登录后投票
时间:2005-03-15
那位仁兄有没有《java深度历险》电子板呀?
   
0 请登录后投票
时间:2005-03-15
我也看了深度历险,却没有楼主那么细心,要向你学习啊
   
0 请登录后投票
时间:2005-03-17
直接调用类的一个静态方法,看看其他的静态方法是否会执行,从这里就可以看出静态方法的执行和类的实例化无关,而是和类的初始化操作有关。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐