当前位置: 首页 > 知识库问答 >
问题:

为什么对父构造函数的调用不是编译器为内部类生成的构造函数中的第一个调用?

梁研
2023-03-14

考虑以下Test类来演示Java中的内部类行为。主代码在run方法中。其余的只是管道代码。

 public class Test {

        private static Test instance = null;

        private Test() {
        }

        private void run() {
            new Sub().foo();  
        }

        public static void main(String[] args) {
            instance = new Test();
            instance.run();
        }

        class Super {
            protected void foo() {
                System.out.println("Test$Super.Foo");
            }
        }

        class Sub extends Super {
            public void foo() {
                System.out.println("Test$Sub.Foo");
                super.foo();
            }
        }
    }

我只是打印下面的javap输出隐藏的构造函数:

so.Test$Sub(so.Test);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #1                  // Field this$0:Lso/Test;
       5: aload_0       
       6: aload_1       
       7: invokespecial #2                  // Method so/Test$Super."<init>":(Lso/Test;)V
  10: return   

通常情况下,编译器确保子类构造函数在初始化自己的字段之前首先调用超类构造函数。这有助于正确构造对象,但我发现编译器为内部类生成的构造函数与规范行为不符。为什么会这样?是否由JLS指定?

附言:我知道内部类包含对外部类的隐藏引用,该引用在上面的javap输出中设置。但问题是为什么在调用超级构造函数之前设置它。我错过了什么?

共有1个答案

董高逸
2023-03-14

内部类是一种抽象,对Java程序员来说应该尽可能透明。考虑下面的类结构,并考虑如果在调用内部类的超级构造函数之后设置< <代码> $字段会发生什么。

class Foo {
  Foo() { System.out.println(foo()); }

  String foo() { return "foo"; }
}

class Bar {
  String bar() { return "bar"; }

  class Qux extends Foo {
    @Override 
    String foo() { return bar(); }
  }
}

注意类Qux中被重写的方法如何调用其外部类Bar的方法。要使其工作,必须在调用Foo的超级构造函数之前设置保存实例的$this字段。否则,由于字段尚未初始化,您将得到一个NullPointerException。为了更清楚地说明这一点,请查看Qux实例的任何实例的以下调用链:

Qux() -> Foo() -> this.foo() -> $this.bar()

作为一个不熟悉内部类实现的程序员,您会想知道这个异常是从哪里来的。为了使内部类抽象透明,您必须首先设置字段,否则您将陷入一个非常漏洞百出的抽象。我不认为这使上述示例成为一个很好的实现,但它是合法的。

 类似资料:
  • 我总是得到与此类似的结果。为什么第一个电话比其他电话要花10倍的时间?

  • 我在班里学习。出于好奇,我扩展了具有参数化构造函数的内部类。但是当我编写super(inti)来调用它时,代码不会编译。 因为内部类是外部类的一部分(成员),必须通过外部类访问它们。如何调用测试类的超级构造函数。 编译错误是:由于某些中间构造函数调用,没有外部类型的封闭实例可用

  • 如果将移到构造函数的最后一行,我不明白为什么下面的代码会显示错误。 我已经检查了很多关于StackOverflow的答案,但我仍然不能理解这其中的原因。请帮我用一些简单的例子和解释弄清楚这个错误。

  • 根据我的理解,当创建了临时对象时,将调用move构造函数。这里,函数返回一个临时对象,但我的程序没有打印来自移动构造函数的消息:

  • 问题内容: 我在Java中使用多个构造函数时遇到麻烦。 我想做的是这样的: 但是我不能,因为第二个构造函数不能调用另一个构造函数,除非它是第一行。 这种情况的常见解决方案是什么?我无法“在线”计算arg2和arg3。我以为也许可以创建一个构造助手方法来完成实际的构造,但是我不确定这是否“漂亮”…… 编辑 :由于我的某些字段是最终的,因此使用辅助方法也是有问题的,我无法使用辅助方法进行设置。 问题答

  • 可能的重复: 为什么this()和super()必须是构造函数中的第一条语句? 为什么子类构造函数必须显式调用超类构造函数?这是什么原因呢?