【JAVA】static块到底什么时候执行?

个人测试:

1.

Class c = staticPack.Word.class;

与 Class.forName("staticPack.Word",false,off.getClass().getClassLoader());

结果一致,显示结果为:

Loaded Office
类别准备载入
类别准备实例化
Word static initialization!

2.

Class c = Class.forName("staticPack.Word");

与 Class.forName("staticPack.Word",true,off.getClass().getClassLoader());

结果一致,显示结果为:

Loaded Office
类别准备载入
Word static initialization!
类别准备实例化

3.异常报错,显示调用的类

3.1 Class c = Class.forName("staticPack.Word",true,off.getClass().getClassLoader());

在Word。java中报错

static{ String a = null; System.out.println(a.equals("")+"Word static initialization!"); }

显示错误信息:

Loaded Office 类别准备载入 Exception in thread "main" java.lang.ExceptionInInitializerError at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at staticPack.Office.main(Office.java:13) Caused by: java.lang.NullPointerException at staticPack.Word.(Word.java:7) ... 3 more

说明没有调用默认调用了Class。forName()这个方法

3.2 Class c = Class.forName("staticPack.Word2",false,off.getClass().getClassLoader());

显示错误信息:

Loaded Office 类别准备载入 类别准备实例化 Exception in thread "main" java.lang.ExceptionInInitializerError at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at java.lang.Class.newInstance0(Unknown Source) at java.lang.Class.newInstance(Unknown Source) at staticPack.Office.main(Office.java:17) Caused by: java.lang.NullPointerException at staticPack.Word.(Word.java:7) ... 7 more

出错信息是在调用newInstance0的时候出错,要是没有调用。程序正常运行。只是加载了类的信息。

总结:

那说明了静态块,只是在调用newInstance0方法时候才会去触发。

========================================================

"java深度历险"一书在讲解“类装载”的一章中,举了以下的例子:

引用

Java代码
  1. public interface Assembly{
  2. public void start();;
  3. }
  4. public class Word implements Assembly{
  5. static{
  6. System.out.println("Word static initialization!");;
  7. }
  8. public void start();{
  9. System.out.prinlnt("Word starts");;
  10. }
  11. }
  12. public class Office{
  13. public static void main(String args[]); throws Exception{
  14. Office off = new Office();;
  15. System.out.println("类别准备载入");;
  16. Class c = Class.forName(args[0],true,off.getClass();.getClassLoader(););;
  17. System.out.println("类别准备实例化");;
  18. Object o = c.newInstance();;
  19. Object o2= c.newInstance();;
  20. }
  21. }
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();; } }执行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方法时,静态初始化块才被真正调用,应该改成-静态初始化块只是在类被第一次实体化的时候才会被仅仅调用一次。”



其实,该书作者的上述描述有误。通过一个试验,就可以看出谬误所在。

Java代码
  1. public class TestA{
  2. static{
  3. System.out.println("Static block executed!");;
  4. }
  5. }
  6. public class Test{
  7. public static void main(String args[]);{
  8. Test test = new Test();;
  9. Class.forName("TestA",true,test.getClass();.getClassLoader(););;
  10. }
  11. }
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(););; } }

运行一下,相信大家一定可以看到,“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块的绝对不是什么“只是在类被第一次实体化的时候才会被仅仅调用一次”,而应该是在类被初始化的时候,仅仅调用一次。

你可能感兴趣的:(【JAVA】static块到底什么时候执行?)