【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.<clinit>(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.<clinit>(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块的绝对不是什么“只是在类被第一次实体化的时候才会被仅仅调用一次”,而应该是在类被初始化的时候,仅仅调用一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值