我有以下代码:

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方法时打印不同的结果.为什么在这种情况下Main方法的放置会影响打印到屏幕上的结果?

推荐答案

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

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

请注意,首先创建的是Bar(尽管首先调用的是Foo‘S构造函数).new指令导致类被初始化(参见spec),not是构造函数调用.当一个类被初始化时,它的静态初始化器运行(见spec).

如果您不知道,非静态内部类是通过让构造函数接受一个额外的参数来实现的,该参数用作封闭实例.new Foo().new Bar()基本上等于new Foo.Bar(new Foo()),但只有前一种语法才有效.

我不确定这样的输出是否符合规范中的行为guaranteed.从技术上讲,它的编译方式可以使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中要初始化的类或接口T的所有条件:

  • T是一个类,并且创建了T的一个实例.

  • 调用由T声明的静态方法.

  • 由T声明的静态字段被赋值.

  • 使用由T声明的静态字段,并且该字段不是常量变量(§4.12.4).

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

Java相关问答推荐

JPackage-results已安装-如何添加系统属性?

JPackaged应用程序启动MSI调试,然后启动System. exit()

强制Mockito返回null而不是emtpy list

Junit with Mockito for java

解析Javadoc时链接的全限定类名

是否在允许数组元素为空时阻止 idea 为空性警告?

AssertJ Java:多条件断言

如何创建一个2d自上而下的移动系统,其中移动,同时持有两个关键是可能的处理?

JavaFX如何在MeshView中修复多个立方体?

如何从错误通道回复网关,使其不会挂起

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

在添加AdMob时无法为Google Play构建应用程序包:JVM垃圾收集器崩溃和JVM内存耗尽

将PNG转换为位图自定义十六进制字符串

如何在Java中为thunk创建映射器函数

向Java进程发送`kill-11`会引发NullPointerException吗?

在Java泛型中使用通配符时,如何推断类型

如何使用WebEnvironment.RANDOM_PORT获得第二个随机端口?

JXBrowser是否支持加载Chrome扩展?

如何修复Spring Boot应用程序中的RestDocumentationGenerationException:java.io.FileNotFoundException:/curl-request.adoc(只读文件系统)?

如何使用Hibernate v6.2构建NamingStrategy,以表名作为所有列的前缀?