抽象クラスをインスタンス化できないというのは本当ですか?
はい。
JVMは内部的に抽象クラスのオブジェクトを作成していますか?
いいえ、しかし、それはよくある誤解です (そして、それを行うのに不合理な方法はありません。JavaScript のような原型的な言語はそのように行います)。
JVM は、作成したクラス (この場合は ) のオブジェクトを1 つConcreteClass
作成します。その 1 つのオブジェクトには、そのスーパークラス ( MyAbstractClass
) とそのサブクラス ( ConcreteClass
) から取得する側面がありますが、オブジェクトは 1 つしかありません。
オブジェクトは、サブクラスによってオーバーライドされるスーパークラスのメソッドなど、同じ名前を持つように見える部分を含む、そのすべての部分の集合体です。実際、これらのメソッドには異なる完全修飾名があり、互いに競合することはありません。そのため、オーバーライドされたメソッドのスーパークラスのバージョンを呼び出すことができます。
オブジェクトが 1 つだけの場合、なぜMyAbstractClass
のコンストラクターへの呼び出しが表示されるのでしょうか。これに答える前に、Java コンパイラーが行っている、ソース・コードには表示されないいくつかのことについて言及する必要があります。
のデフォルトコンストラクタを作成していますConcreteClass
。
そのコンストラクターでは、MyAbstractClass
コンストラクターを呼び出しています。
念のため:コンストラクターでは、コンストラクター内に呼び出しが記述されていないためMyAbstractClass
、スーパークラスの ( ) コンストラクターへの呼び出しを追加しています。Object
super(...)
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 つのオブジェクトに対して必要な数のコンストラクター (実際には初期化子と呼ばれる必要があります) を実行して、各スーパークラスにオブジェクトのその部分を初期化する機会を与えます。
したがって、そのコードで何が起こるか (完全に理解するために、デバッガーでこれをステップ実行できます) は次のとおりです。
JVM はオブジェクトを作成します
ConcreteClass
コンストラクターが呼び出されます
コンストラクターが最初に行うことは、そのスーパークラスのコンストラクター (この場合は のコンストラクター) を呼び出すことMyAbstractClass
です。(これは絶対的な要件であることに注意してください。Java コンパイラでは、スーパークラス コンストラクター呼び出しの前に、コンストラクター自体にロジックを含めることはできません。)
コンストラクターが最初に行うことは、そのスーパークラスのコンストラクター ( Object
's)を呼び出すことです。
Object
コンストラクターが戻ると、コンストラクターの残りの部分が実行MyAbstractClass
されます
MyAbtractClass
コンストラクターが戻ると、コンストラクターの残りの部分が実行ConcreteClass
されます
オブジェクトは、new ConcreteClass()
式の結果として返されます。
イニシャライザを持つインスタンス フィールドがある場合、上記はより複雑になることに注意してください。詳細については、JLS および JVM の仕様を参照してください。