【问题标题】:Why does java not initialise static nested class fields at the same time as static outter fields?java 为什么不初始化静态嵌套类字段和静态外部字段?
【发布时间】:2019-09-03 04:01:31
【问题描述】:

Java 在与该类交互时初始化外部类静态字段,但不初始化嵌套的静态类字段。

所以我已经阅读了嵌套类文档:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html,我认为它归结为这一行:

实际上,静态嵌套类在行为上是一个顶级类,为了方便打包,它已经嵌套在另一个顶级类中。

如果我的理解是正确的,这意味着 java 将我下面的两个类视为单独的实体;

public class OutterClass {

    private static final OutterClass outterField = new OutterClass("outterField");

    private OutterClass(String string) {
        System.out.println(string + " has been initialised");
    }

    private static class InnerClass {
        private static final OutterClass innerField = new OutterClass("innerField");
    }

    public static void foo() {}
}

这意味着当我通过调用Outer.foo()OuterClass 交互时,java 将初始化我的静态字段,因为它是OuterClass 的一部分。但由于它将InnerClass 视为一个单独的顶级类,InnerClass 的字段不会被初始化。

1) 我的理解正确吗?

2) 这与 JIT 编译器或类加载器有什么关系吗?加载OuterClass 时是否加载了InnerClass

谢谢

【问题讨论】:

  • 1) 是(编译内部类并创建一个单独的类文件,最终使用一些合成方法来创建一个不同的类,以允许从外部类访问私有成员); 2) no 或 no,no(对于 VM,它只是一个普通的 separate 类 - 编译器完成了所有 magic
  • 您能否将此添加为答案,以便我接受。我检查了我的类文件,你是对的,它确实为InnerClassOuterClass 构建了两个单独的类文件。现在更有意义的是为什么 InnerClass.innerField 没有初始化,因为它在物理上位于单独的文件中。

标签: java static initialization


【解决方案1】:

1) 我的理解正确吗?

基本上是的。考虑一下您的static 成员outerField 会发生什么:

public class OutterClass {

    private static final OutterClass outterField = new OutterClass("outterField");

理论上,JVM 可能会在程序开始运行或加载类时创建 static final 对象,但事实并非如此。相反,它只会在需要时初始化它——基本上:

  • 类的实例已创建,或
  • 类的静态字段或方法之一被访问

(见https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1

静态内部类也是如此。正如你所说,JVM将其视为顶级内部类,因此仅在需要时才初始化其成员。

2) 这与 JIT 编译器或类加载器有什么关系吗?

没有,也没有。静态成员的初始化不是在类加载时进行,而是在稍后进行(正如我们所说,在访问类时)。这不是编译器优化的问题,而是明确指定的行为。毕竟,当您加载一个可能很大的类库时,您不希望您的 JVM 消耗内存或时间来初始化您的程序从未接触过的所有类的静态成员; only-on-demand 是一种更好的方法。

加载OuterClass时是否加载InnerClass?

是(但当时没有初始化)

【讨论】:

  • 啊,好电话,看起来 JLS 为 JVM 实现打开它来解析(因此加载)类“急切”或“延迟”(docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4)例如,OutterClass , 很可能不会触发 InnerClass 的加载,尤其是因为从未使用过 InnerClass 是一种不寻常的情况。如果OutterClass 有返回InnerClass 的方法,那么很可能会触发类加载来解决它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多