匿名 class 的隐式构造函数,其 super class 是内部 Class

Implicit constructor in case of anonymous class whose super class is an Inner Class

考虑 JLS 中的以下文章:§15.9.5.1 当匿名 class 扩展内部 class - 那么对于匿名 class 的隐式构造函数 - 以下是关于隐式构造函数主体的规则:

The constructor body consists of an explicit constructor invocation (§8.8.7.1) of the form o.super(...), where o is the first formal parameter of the constructor, and the actual arguments are the subsequent formal parameters of the constructor, in the order they were declared.

以下是我们从这里了解到的-:

  1. o - 是 class 的实例 - 仅包含匿名 class.
  2. 的超级 class
  3. 当我们执行 o.super(...) 时,我们实际上是在调用封闭实例的超级 class。

考虑以下程序:

class A_ {
  public A_(Boolean st){}
  public class B_ {
    public B_(Integer a){}
    public class C_ {
      public C_(String str){}
    }
  }
}

//when creating the anonymous constructor out of C - in a separate class:
public class ThisInAnonymousTesting {
  public static void main(String[] args) {
    A_.B_.C_ member =
        new A_(true)
            .new B_(23)
            .new C_("Hey"){
    };
  }
}

现在当我们反编译 anonymous class 时,我们得到以下内容:

/**
 === Anonymous class Declaration
*/
import A_.B_;
import A_.B_.C_;

final class ThisInAnonymousTesting extends C_ {
// - Rule : the 1st argument is the class instance which is the enclosing instance
// of the Super class(C in this case) - ie B
    ThisInAnonymousTesting(B_ x0, String str) {
        x0.getClass();

//But the super() invocation here is for the super class - not for the enclosing instance
        super(x0, str);
    }
}

以下是我的问题:

  1. 为什么我们需要做 o.super(...) - 当我们已经将 o 的初始化实例传递给匿名 class 构造函数时?
    • ie o 只有在它的超 classes 已经被调用时才会被创建。
    • 构造函数中的 super() 调用显然是在尝试实例化 class C_ 这很好 - 因为它是当前匿名 class 的超级 class.
  2. 在反编译版本中,x0.getClass();是什么意思——我的意思是为什么JVM需要做getClass()

不确定我对 o.super() 子句的解释是否正确?

我想你误解了o.super(...)的意思。报表报表:

ExpressionName . [TypeArguments] super ( [ArgumentList] ) ; 
Primary . [TypeArguments] super ( [ArgumentList] ) ;

是合格的超级class 构造函数调用,并在 JLS 的 explicit constructor invocations 部分中指定。

它不调用o 的超级class 构造函数。它调用封闭 class 的超级 class 构造函数,其中 o 作为 封闭实例 .

这是一个简单的例子:

class Outer {
    public static final Outer OUTER1 = new Outer(1);
    public static final Outer OUTER2 = new Outer(2);
    public Outer(int x) {
        this.x = x;
    }

    private final int x;

    class Inner {
        public Inner() {
            System.out.println("In Inner constructor, the enclosing instance's field x is: " + x);
        }
    }

    class InnerSubclass extends Inner {
        public InnerSubclass() {
            OUTER1.super();

            System.out.println("In InnerSubclass constructor, the enclosing instance's field x is: " + x);
        }
    }
}

如果你Outer.OUTER2.new InnerSubclass();,输出是:

In Inner constructor, the enclosing instance's field x is: 1
In InnerSubclass constructor, the enclosing instance's field x is: 2

OUTER1.super(); 调用 Inner 的构造函数(OUTER1 是封闭对象),而不是 Outer 的构造函数。请注意,这与仅执行 super(); 不同,因为这将使用 InnerSubclass 的封闭实例来调用 superclass 构造函数,无论它是什么,不一定 OUTER1.

所以规范所说的是匿名构造函数将调用超级class'构造函数,封闭实例是匿名构造函数的第一个参数.匿名构造函数的第一个参数是什么?这是在几行之前说明的:

Otherwise, the first formal parameter of the anonymous constructor represents the value of the immediately enclosing instance of i with respect to S

在你的情况下,new A_(true).new B_(23)

所以整体效果是这样的:

final class ThisInAnonymousTesting extends C_ {

    ThisInAnonymousTesting(B_ o, String str) {
        o.super(str); // recall that this calls C's constructor
    }
}

// the callsite now becomes like this:
A_.B_.C_ member = new ThisInAnonymousTesting(new A_(true).new B_(23), "Hey");

注意:ThisInAnonymousTesting extends C_ 无效 Java,但在字节码中是允许的。

在反编译代码中,你看到语法super(x0, str);,因为字节码中没有内部classes。内部 classes 的封闭实例都只是转换为私有字段,并通过构造函数的第一个参数进行分配。因此,如果您查看字节码,o.super(...) 实际上只是 super(o, ...)

考虑:

class Outer {
    class Inner {}
}

Outer$Inner.class 的字节码是:

class Outer$Inner {
  final Outer this[=15=];

  Outer$Inner(Outer);
    Code:
       0: aload_0          
       1: aload_1          
       2: putfield      #1 // this.this[=15=] = Outer parameter (aka enclosing instance)
       5: aload_0          
       6: invokespecial #7 // super()
       9: return
}