簡體   English   中英

匿名 class 的隱式構造函數,其超級 class 是內部 Class

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

考慮 JLS 中的以下文章:§15.9.5.1 當匿名 class 擴展內部 class - 然后對於匿名 class 的隱式構造函數的隱式構造函數:以下是關於主體構造函數的規則:

構造函數體由o.super(...)形式的顯式構造函數調用(第 8.8.7.1 節)組成,其中o是構造函數的第一個形參,實際的 arguments 是構造函數的后續形參,按照它們被聲明的順序。

以下是我們從中了解到的——:

  1. o - 是 class 的實例 - 僅包含匿名 class 的超級 class。
  2. 當我們執行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"){
    };
  }
}

現在,當我們反編譯匿名 class時,我們得到以下信息:

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

final class ThisInAnonymousTesting$1 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$1(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 構造函數時?
    • o僅在它的超類已經被調用時才被創建。
    • 構造函數中的super()調用顯然試圖實例化 class C_這很好 - 因為它是當前匿名 class 的超級 class。
  2. 在反編譯的版本中,需要什么x0.getClass(); - 我的意思是為什么 JVM 需要做getClass()

不確定我對o.super()子句的解釋是否正確?

我認為您誤解了o.super(...)的含義。 forms的聲明:

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

是限定的超類構造函數調用,並在 JLS 的顯式構造函數調用部分中指定。

它不調用o的超類構造函數。 它調用封閉類的超類構造函數,其中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(); ,output為:

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的封閉實例來調用超類構造函數,無論它可能是什么,不一定是OUTER1

所以規范的真正含義是匿名構造函數將調用超類的構造函數,封閉實例是匿名構造函數的第一個參數 匿名構造函數的第一個參數是什么? 這在之前的幾行中已經說明:

否則,匿名構造函數的第一個形參表示i相對於S的直接封閉實例的值

在您的情況下, new A_(true).new B_(23)

所以這個的整體效果是這樣的:

final class ThisInAnonymousTesting$1 extends C_ {

    ThisInAnonymousTesting$1(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$1(new A_(true).new B_(23), "Hey");

注意: ThisInAnonymousTesting$1 extends C_是無效的 Java,但在字節碼中是允許的。

在反編譯的代碼中,您會看到語法super(x0, str); 因為字節碼中沒有內部類。 內部類的封閉實例都只是轉換為私有字段,並通過構造函數的第一個參數進行分配。 因此,如果您查看字節碼, o.super(...)實際上只是super(o, ...)

考慮:

class Outer {
    class Inner {}
}

Outer$Inner.class 的字節碼是:

class Outer$Inner {
  final Outer this$0;

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM