为了账号安全,请及时绑定邮箱和手机立即绑定

请问Java中的静态/实例初始化块按照什么顺序运行?

请问Java中的静态/实例初始化块按照什么顺序运行?

侃侃尔雅 2019-08-02 07:02:59
Java中的静态/实例初始化块按照什么顺序运行?假设一个项目包含几个类,每个类都有一个静态初始化块。这些块按什么顺序运行?我知道,在类中,这样的块是按照它们在代码中出现的顺序运行的。我读过不同的类都是一样的,但是我编写的一些示例代码不同意这一点。我使用了这个代码:package pkg;public class LoadTest {     public static void main(String[] args) {         System.out.println("START");         new Child();         System.out.println("END");     }}class Parent extends Grandparent {     // Instance init block     {         System.out.println("instance - parent");     }     // Constructor     public Parent() {         System.out.println("constructor - parent");     }     // Static init block     static {         System.out.println("static - parent");     }}class Grandparent {     // Static init block     static {         System.out.println("static - grandparent");     }     // Instance init block     {         System.out.println("instance - grandparent");     }     // Constructor     public Grandparent() {         System.out.println("constructor - grandparent");     }}class Child extends Parent {     // Constructor     public Child() {         System.out.println("constructor - child");     }     // Static init block     static {         System.out.println("static - child");     }     // Instance init block     {         System.out.println("instance - child");     }}得到了这个输出:启动静态祖父母静态亲本静态子实例-祖父母构造师-祖父母实例-父母构造函数-父实例-儿童构造函数-子端部显而易见的答案是,父母的街区跑在他们的孩子之前,但这可能只是一个巧合,如果两个班级不属于同一等级,那就没有帮助了。编辑:我修改了示例代码,将其附加到LoadTest.java:class IAmAClassThatIsNeverUsed {     // Constructor     public IAmAClassThatIsNeverUsed() {         System.out.println("constructor - IAACTINU");     }     // Instance init block     {         System.out.println("instance - IAACTINU");     }     // Static init block     static {         System.out.println("static - IAACTINU");     }}正如类名所暗示的那样,我从未在任何地方引用过新类。新程序产生了与旧程序相同的输出。
查看完整描述

3 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞



类的静态初始化程序在首次访问类时运行,可以创建实例,也可以访问静态方法或字段。

因此,对于多个类,这完全取决于运行的代码导致这些类被加载。



查看完整回答
反对 回复 2019-08-03
?
慕标5832272

TA贡献1966条经验 获得超4个赞

见“公约”第12.4和12.5节JLS第8版,他们详细介绍了所有这些(静态变量为12.4,例如变量为12.5)。

用于静态初始化(第12.4节):

类或接口类型T将在第一次出现以下情况之前立即初始化:

  • T是一个类,并创建了一个T的实例。
  • T是一个类,调用T声明的静态方法。
  • 指定一个由T声明的静态字段。
  • 使用由T声明的静态字段,且该字段不是常量变量(§4.12.4)。
  • t是一个顶级类(§7.6),执行在T(§8.1.3)中以词汇方式嵌套的断言语句(§14.10)。

(还有几个脏话从句

查看完整回答
反对 回复 2019-08-03
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

基思和克里斯的答案都很好,我只是为我的具体问题增加一些细节。

静态init块按照初始化类的顺序运行。那是什么顺序?JLS 12.4.1:

类或接口类型T将在第一次出现以下情况之前立即初始化:

  • T是一个类,并创建了一个T的实例。
  • T是一个类,调用T声明的静态方法。
  • 指定一个由T声明的静态字段。
  • 使用由T声明的静态字段,且该字段不是常量变量(§4.12.4)。
  • T是一个顶级类,在T中执行一个按词法嵌套的断言语句(§14.10)。

类和包中某些反射方法的调用还会导致类或接口初始化。在任何其他情况下都不会初始化类或接口。

为了举例说明,下面是示例中正在发生的事情的演练:

  1. 进入主
  2. 打印“开始”
  3. 尝试创建第一个需要初始化子实例的实例

  4. 尝试初始化子节点会导致父级初始化

  5. 尝试初始化父级会导致祖父母的初始化。

  6. 在祖父母初始化开始时,运行祖父母的静态初始化块

  7. 从技术上讲,Object在初始化链中获得了最后的发言权,因为它是祖父母的父级,但是它没有什么可贡献的。

  8. 在祖父母的静态初始化块结束后,程序回到父程序的静态初始化块

  9. 在父程序的静态初始化块结束后,程序返回到child的静态初始化块

  10. 此时,初始化了child,因此它的构造函数可以继续

  11. 由于IAmAClassThatIsNeverUsed从未被引用过,因此它的任何代码都不会运行,包括静态初始化程序块。

  12. 本演练的其余部分与静态初始化器无关,仅为完整性而包含
  13. 子构造函数隐式调用Super()(即父构造函数)
  14. 父构造函数隐式调用Super()(即祖父母的构造函数)
  15. 祖父母的构造函数也是这样,没有任何效果(同样,对象没有任何贡献)
  16. 在祖父母的构造函数调用Super()之后,爷爷奶奶的实例初始化程序块立即出现
  17. 爷爷奶奶的构造函数的其余部分运行,构造函数终止
  18. 程序返回到父构造函数,在调用Super()(即祖父母的构造函数)后立即解析
  19. 如前所述,父实例初始化程序完成了它的工作,它的构造函数也完成了。
  20. 类似地,程序返回并完成child的构造函数
  21. 此时,对象已被实例化。
  22. 打印“结束”
  23. 正常终止


查看完整回答
反对 回复 2019-08-03
  • 3 回答
  • 0 关注
  • 241 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信