java - 在外部类和内部类之间,在外部类内部或外部调用 main 方法时,它们的静态初始化程序运行顺序不同

标签 java inner-classes static-initializer

我有以下代码:

class Foo {
    static { //static initializer block
        System.out.print("Foo");
    }
    class Bar {
        static { //static initializer block
            System.out.print("Bar");
        }
    }

    public static void main(String[] args) { // => This will print "FooBar" to the console
        new Foo().new Bar();
    }
}

public class Main {

    public static void main(String[] args) { // This will print "BarFoo" to the console
        new Foo().new Bar();
    }
}

正如注释所说,它们将在独立调用主方法时打印不同的结果。为什么在这种情况下 main 方法的放置会影响打印到屏幕上的结果?

最佳答案

new Foo().new Bar() 被编译为以下字节码:

NEW Foo$Bar
DUP
NEW Foo
DUP
INVOKESPECIAL Foo.<init> ()V
INVOKESPECIAL Foo$Bar.<init> (LFoo;)V

请注意,首先创建的是 Bar(尽管首先调用的是 Foo 的构造函数)。 new 指令导致类被初始化(参见 spec ),而不是构造函数调用。当初始化一个类时,它的静态初始化程序会运行(请参阅 spec )。

以防万一您不知道,非静态内部类是通过让构造函数采用额外参数来实现的,该参数用作封闭实例。 new Foo().new Bar() 基本上是在说 new Foo.Bar(new Foo()),但只有前一种语法才有效。

我不确定这样的输出是否是规范所保证的行为。从技术上讲,它可以以先出现 NEW Foo 的方式进行编译,但这需要一个额外的变量,就像您编写的那样:

var f = new Foo();
f.new Bar();

因此,当您将 new Foo().new Bar() 放入不相关的类中时,Bar 首先被初始化,因此 Bar首先打印。

但是,当您将 new Foo().new Bar() 放入 Foo 中声明的静态方法中时,Foo 将被初始化在任何 new 指令之前,因此首先打印 Foo。这是因为在 Foo 中调用静态方法会导致 Foo 被初始化。

查看要在 spec 中初始化类或接口(interface) T 的所有条件:

  • T is a class and an instance of T is created.

  • A static method declared by T is invoked.

  • A static field declared by T is assigned.

  • A static field declared by T is used and the field is not a constant variable (§4.12.4).

请注意,第一个指的是 new 指令的执行,而不是构造函数调用。

关于java - 在外部类和内部类之间,在外部类内部或外部调用 main 方法时,它们的静态初始化程序运行顺序不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77148390/

相关文章:

rust - 使用宏初始化大量非复制元素

java - (Java) 类的数组

java - 为用户电子邮件获取空值 - restfb

java - 使用现有的 ant build.xml 文件创建一个 eclipse 项目

c++ - 错误 C6011 :Dereferencing NULL pointer 'NAME' . C++

php - 我应该如何弥补 PHP 中静态初始化器的不足?

java - 在 ConcurrentHashMap.computeIfPresent 中执行 `remappingFunction`

java - 在Java中,如何访问新监听器 block 内的静态方法参数?

java - 非静态内部类对象在不再被引用后会被垃圾回收吗?

Java - 来自静态初始化 block 内部的类类型