3

抽象クラスとその具体的なサブクラスがあり、サブクラスのオブジェクトを作成すると、自動的にスーパー コンストラクターが呼び出されます。JVM は抽象クラスのオブジェクトを内部的に作成していますか?

public abstract class MyAbstractClass {

    public MyAbstractClass() {
        System.out.println("abstract default constructor");
    }

}
public class ConcreteClass extends MyAbstractClass{

    public static void main(String[] args) {
        new ConcreteClass();
    }

}

それでは、JVMにオブジェクトなしでコンストラクターがどのように存在するのですか?? (抽象クラスの場合)

また、オブジェクトが作成された後にコンストラクターが実行され、抽象クラスのオブジェクトを作成せずに、デフォルトのコンストラクターがどのように実行されるのですか?? (これはJava Docに記載されています)

4

3 に答える 3

7

抽象クラスをインスタンス化できないというのは本当ですか?

はい。

JVMは内部的に抽象クラスのオブジェクトを作成していますか?

いいえ、しかし、それはよくある誤解です (そして、それを行うのに不合理な方法はありません。JavaScript のような原型的な言語はそのように行います)。

JVM は、作成したクラス (この場合は ) のオブジェクトを1 つConcreteClass作成します。その 1 つのオブジェクトには、そのスーパークラス ( MyAbstractClass) とそのサブクラス ( ConcreteClass) から取得する側面がありますが、オブジェクトは 1 つしかありません。

オブジェクトは、サブクラスによってオーバーライドされるスーパークラスのメソッドなど、同じ名前を持つように見える部分を含む、そのすべての部分の集合体です。実際、これらのメソッドには異なる完全修飾名があり、互いに競合することはありません。そのため、オーバーライドされたメソッドのスーパークラスのバージョンを呼び出すことができます。

オブジェクトが 1 つだけの場合、なぜMyAbstractClassのコンストラクターへの呼び出しが表示されるのでしょうか。これに答える前に、Java コンパイラーが行っている、ソース・コードには表示されないいくつかのことについて言及する必要があります。

  1. のデフォルトコンストラクタを作成していますConcreteClass

  2. そのコンストラクターでは、MyAbstractClassコンストラクターを呼び出しています。

  3. 念のため:コンストラクターでは、コンストラクター内に呼び出しが記述されていないためMyAbstractClass、スーパークラスの ( ) コンストラクターへの呼び出しを追加しています。Objectsuper(...)MyAbstractClass

以下は、Java コンパイラーが追加するビットを入力したコードの外観です。

public abstract class MyAbstractClass {

    public MyAbstractClass() {
        super();           // <== The Java compiler adds this call to Object's constructor (#3 in the list above)
        System.out.println("abstract default constructor");
    }

}
public class ConcreteClass extends MyAbstractClass{

    ConcreteClass() {      // <== The Java compiler adds this default constuctor (#1 in the list above)
        super();           // <== Which calls the superclass's (MyAbstractClass's) constructor (#2 in the list above)
    }

    public static void main(String[] args) {
        new ConcreteClass();
    }

}

さて、それはさておき、 TheLostMindがコメントで非常に便利に言及した点に触れましょう:コンストラクターはオブジェクトを作成せず、初期化します。JVM はオブジェクトを作成し、その 1 つのオブジェクトに対して必要な数のコンストラクター (実際には初期化子と呼ばれる必要があります) を実行して、各スーパークラスにオブジェクトのその部分を初期化する機会を与えます。

したがって、そのコードで何が起こるか (完全に理解するために、デバッガーでこれをステップ実行できます) は次のとおりです。

  1. JVM はオブジェクトを作成します

  2. ConcreteClassコンストラクターが呼び出されます

    1. コンストラクターが最初に行うことは、そのスーパークラスのコンストラクター (この場合は のコンストラクター) を呼び出すことMyAbstractClassです。(これは絶対的な要件であることに注意してください。Java コンパイラでは、スーパークラス コンストラクター呼び出しの前に、コンストラクター自体にロジックを含めることはできません。)

      1. コンストラクターが最初に行うことは、そのスーパークラスのコンストラクター ( Object's)を呼び出すことです。

      2. Objectコンストラクターが戻ると、コンストラクターの残りの部分が実行MyAbstractClassされます

    2. MyAbtractClassコンストラクターが戻ると、コンストラクターの残りの部分が実行ConcreteClassされます

  3. オブジェクトは、new ConcreteClass()式の結果として返されます。

イニシャライザを持つインスタンス フィールドがある場合、上記はより複雑になることに注意してください。詳細については、JLS および JVM の仕様を参照してください。

于 2015-05-08T13:53:12.593 に答える
1

JVMは、抽象クラスのフィールドとメソッドを継承する具象クラスのインスタンスである1つのオブジェクトを作成します

于 2015-05-08T13:54:41.997 に答える