11

内部クラスに関係するコンストラクターがあるかどうか知りたいです。たとえば、以下のコードスニペットについて考えてみます。

class MyOuter
{
   private int x= 10;

   class MyInner
   {
      void dostuff(){
         System.out.println("The value of x is "+x);
      }
   }
}

別のJavaファイルでは、以下に示すように、MyOuterクラスとMyInnerクラスの両方のインスタンスを作成します。

Class Program
{
   public static void main(String [] args)
   {
      MyOuter mo = new MyOuter();
      MyOuter.MyInner mi = mo.new MyInner();
      mi.dostuff();
   }
}

上記のコードスニペットは正常にコンパイルされ、「xの値は10です」という出力が得られます。

ここで知りたいのは、New()がMyInnerクラスとMyOuterクラスで使用されたときにコンストラクターが呼び出されるかどうかです。はいの場合、内部クラスから外部クラスにチェーンするコンストラクターはありますか(サブクラスがスーパークラスのコンストラクターを呼び出すなど)。

4

5 に答える 5

15

内部クラスを拡張すると、内部クラスのコンストラクター チェーンを確認できます。

次の例を見てください。

public class MainClass {

    public MainClass(String value) {
        System.out.println("mainValue: " + value);
    }

    public class NestedClass {

        public NestedClass(String nestedValue) {
            System.out.println("nestedValue: " + nestedValue);
        }
    }

}

そして、このように NestedClass を拡張します

public class NestedClassExtension extends NestedClass {

    public NestedClassExtension(MainClass mainClass, String nestedValue) {
        mainClass.super(nestedValue);
    }
}

そのため、ネストされたクラスのスーパーコンストラクターを呼び出して、そのコンストラクターに を渡し、オブジェクトインスタンスMainClassを呼び出すことができることがわかります。.supermainClass

これで、次の方法で NestedClassExtension インスタンスを作成できます。

NestedClassExtension extension = new NestedClassExtension(new MainClass("main"), "nested");

したがって、メイン クラスが存在する必要があり、そのコンストラクターが最初に呼び出されます。次に、ネストされたクラスのコンストラクター。

代わりに、NestedClassの外部でインスタンスを作成する場合は、次のMainClassように記述する必要があります。

MainClass mc = new MainClass("main");
mc.new NestedClass("nested");

また、MainClass最初に を作成し、次にネストされたクラスを作成する必要があります。

于 2012-04-13T06:15:27.820 に答える
4

内部コンストラクターは、次の場合にのみ呼び出されます。

MyOuter.MyInner mi = mo.new MyInner(); 

そうしないと、静的ブロックが実行されるようにインスタンス化されないため、内部クラスコンストラクターも呼び出されませんが、オブジェクトを作成するまでインスタンスブロックとコンストラクターは呼び出されません。

于 2012-04-13T05:59:31.360 に答える
2

コンストラクターを指定しない場合、パラメーターをとらないデフォルトのコンストラクターが作成されます。MyInner(int i)と言う他のコンストラクターを宣言すると、デフォルトのコンストラクターの作成は省略され、(必要に応じて)自分で宣言する必要があります。すべてのオブジェクト(例外なし)は、コンストラクターを呼び出すことによって作成されます。

于 2012-04-13T05:59:53.247 に答える
2

これらは両方とも、デフォルトの引数なしコンストラクターを使用してインスタンス化されます。継承のsuper()のような連鎖はありません。最初に外部クラスをインスタンス化せずに内部クラスをインスタンス化することはできないということだけです。

静的内部クラスと非静的内部クラスの違いを読んでください。

于 2012-04-13T06:00:59.487 に答える
1

提案されたコードをコンパイルしてから、その上でJavaデコンパイラーを実行する場合

javap MyOuter$MyInner

コンパイラが実際に内部クラスのコンストラクタを宣言する方法がわかります。

public class MyOuter$MyInner extends java.lang.Object{
    final MyOuter this$0;
    public MyOuter$MyInner(MyOuter);
    void dostuff();
}

ここで、コンパイラが、囲んでいるクラスへの参照を保持するfinalフィールドメンバーを宣言することにより、内部クラスを実装していることがわかります。Innerフィールドはfinalとして宣言されているため、クラスをインスタンス化するための値を指定する必要があります。

これを行うとMyOuter.MyInner mi = mo.new MyInner()、コンパイラーは、囲んでいるインスタンスがパラメーターとして渡されることを確認します。

これはコンパイラによって自動的に行われるため、内部インスタンスを作成するまでに外部インスタンスがすでに存在している必要があるという理由だけで、内部クラスの作成と外部クラスの作成を連鎖させることはできません。

ただし、内部クラスの他の宣言されたコンストラクター間でコンストラクターチェーンを実行することはできます。

たとえば、次のようなコードの場合:

public class MyOuter
{
   private int x= 10;

   public class MyInner
   {
        private int y = 0;

        public MyInner(){
            this(10);
        }

        public MyInner(int value){
            this.y = value;
        }

        void doStuff(){
            System.out.println("The value of x is "+x);
        }
   }
}

ここでは、内部クラスを使用してコンストラクターをチェーンしています。

この場合も、逆コンパイラーはこれらすべてを確実に解釈して、外部インスタンスがパラメーターとして内部インスタンスに渡されるようにします。

public class MyOuter$MyInner extends java.lang.Object{
    final MyOuter this$0;
    public MyOuter$MyInner(MyOuter);
    public MyOuter$MyInner(MyOuter, int);
    void doStuff();
}
于 2012-04-13T06:21:35.960 に答える