Javaでの継承について質問があります。
2つのクラスA
とB
があり、クラスB、inherits from A:
public class A {
public A() {
System.out.println("Hi!");
}
}
public class B extends A {
public B() {
System.out.println("Bye!");
}
public static void main(String[] args) {
B b = new B();
}
}
プログラムBを実行すると、出力は次のようになります。
Hi!
Bye!
Question:
class A
のオブジェクトを作成したときに、class B
の-コンストラクターが呼び出されるのはなぜですか?
BはAからすべてを継承することを知っています-すべてのインスタンスまたはクラス変数、およびすべてのメソッド。この意味で、BのオブジェクトはAのすべての特性に加えて、Bで定義された他のいくつかの特性を持っています。しかし、私は知りませんでした。タイプBのオブジェクトを作成すると、Aのコンストラクターも呼び出されると想像してください。だから、これを書く:
B b = new B();
作成2つのオブジェクト-タイプBとタイプAの1つ。
これは面白くなってきています、
なぜこれが正確に起こるのか誰かが説明できますか?
2つのオブジェクトを作成するのではなく、1つだけを作成します:[〜#〜] b [〜#〜]。
別のクラスから継承する場合は、コンストラクターでmustを呼び出す必要があります。そうしないと、コンパイラは、はっきりとわかるように、その呼び出しを挿入します。
スーパークラスコンストラクターが呼び出されるのは、そうしないと、オブジェクトが初期化されていない状態のままになり、サブクラスの開発者に知られていない可能性があるためです。
コンパイラがスーパーコールを挿入した後、サブクラスは実際には次のようになります。
public class B extends A {
public B() {
super();
System.out.println("Bye!");
}
}
2つのオブジェクトを作成するのではなく、Bのインスタンスを1つだけ作成します。スーパークラスコンストラクターが呼び出される理由は、前述のように、BにはAのすべてのフィールドがあり、これらのフィールドを初期化する必要があるためです。
継承は基本クラスとサブクラスの間の「isa」関係であることに注意してください。したがって、サブクラスのインスタンスがあるたびに、定義上、基本クラスのインスタンスもあります(2つではなく、インスタンスの一部として)個別のインスタンス)。基本クラスを適切に初期化するために、コンストラクターが呼び出されます。
さらに、サブクラスが基本クラスの内部状態に依存している場合にどうなるかを考えてください。その場合、基本クラスのインスタンスを初期化する必要はありませんか?
これは、コンストラクターを使用してオブジェクトを初期化するために行われます。 BもAであるため、最初にAのコンストラクターを呼び出し、次にBのコンストラクターを呼び出します。
補足として、super(arg1, etc)
を使用して、渡すパラメーターの種類に基づいてAのコンストラクターを呼び出すことができます...ただし、コンストラクターの最初の行である必要があります。
2つのオブジェクトを作成するのではなく、1つのオブジェクトを作成するだけです。 bはタイプBおよびタイプAです。コンストラクターは基本的に、私を構築するために必要なことはここにあると言っています。したがって、新しい「B」インスタンスを作成するときは、a B()とA()の両方であるオブジェクトを作成します。次のシナリオを想像してみてください。
class Q {
int i;
public Q() {
// set default value
i= 99;
}
}
class Z extends Q {
public Z() {
}
}
Qのコンストラクターが呼び出されなかった場合、デフォルト値を取得するにはどうすればよいですか?
Aがコンストラクターでメンバーを初期化し、派生クラスでsuperを呼び出すのを忘れた場合、Aのメンバーは悪い状態になっている可能性があります。 Javaは、あなたが自分の足を撃つのを阻止しようとしています。
コンストラクターには、Aのすべての初期化が含まれています。2つのオブジェクトを作成しているわけではありません。 1つのオブジェクトを作成し、スーパークラスの初期化子を実行してそのメンバーを初期化し、次に派生クラスの初期化子を実行してそのメンバーを初期化します。
1つのオブジェクトのみが作成され、両方の請負業者が同じオブジェクトで実行されます。
理由は単純です。BにはAのすべての変数とメソッドがあるので、Aのメソッドが機能するように、Aの変数の一部を初期化する必要がある場合は、誰かがそれを初期化する必要があります。誰かがAのコンストラクターです。
例えば:
public class A {
public A() {
x = 1;
}
private int x;
public int getX() {
return x;
}
}
public class B extends A {
public B() {
}
public static void main(String[] args) {
B b = new B();
System.out.println(b.getX()); // should print 1
}
}
Bを作成しても、余分なAは作成されません。
しかし、Bを作成することにより、B is a Aであるため、一種のAを作成します。
Java/C++は、暗黙的にAのコンストラクターを呼び出します。どうして?言語デザイン。ただし、Aのコンストラクターには初期化が含まれている可能性があるため、これは問題ありません。また、BはAのすべての機能とバグを使用するため、これらの機能は適切に初期化する方が適切です。
クラスのコンストラクターは、ほとんどのOOPで非常に重要な概念です。
クラスは、状態とその状態を操作する手段を提供することにより、不変条件の保守を容易にします。コンストラクターの役割は、クラスをそれらの不変条件に準拠する状態にすることです(または、invliadオブジェクトの使用を禁止します)。コンストラクターは独自の「this」参照を他の場所に渡すことができるため、これは多くの言語で意図されているよりもやや緩いですが、これは少なくともクラスの制御下にあります(したがって、十分に安定して有効な状態にあることがわかりますそれが世界の他の地域にアクセスできるようにするため)
Bは非常に現実的な意味でAであり、Aが提供する任意のメソッドを呼び出すことができるため、継承によってこの複雑さが増します。したがって、AであるBの部分は、Bが調べる前に、自分自身を初期化する機会を得る必要があります。 Aのコンストラクターは、Bコンストラクターの実際の作業が始まる前に呼び出されます。
新しいオブジェクトがcreate(B)の場合、B内にオブジェクトが作成されます(extendsキーワードのため)。 BクラスJVMではBクラスコンストラクターを検索しますが、拡張キーワードのため、スーパークラスコンストラクターに移動します。内部クラスx値が初期化されます。ただし、xはプライベートであるため、外部のクラスthrow getXxx()
メソッドにアクセスして、結果を取得できます。
すべてのスーパークラスにはコンストラクターがあり、階層の上の各コンストラクターは、サブクラスのオブジェクトが作成されたときに実行されます。
サブクラスオブジェクトが作成されると、内部的にはスーパークラスオブジェクト用に作成されませんでしたが、メモリはスーパークラスメンバーに割り当てる必要があります。
Java子クラスのオブジェクトを作成すると、親クラスのコンストラクターが常に呼び出されます。これは、Objectクラスがすべてのスーパークラスの親であり、Objectクラスのコンストラクターを呼び出すと、オブジェクトのみが呼び出されるためです。が作成され、Javaはクラスの場合に複数の継承をサポートしないため、他のクラスを拡張する場合、子クラスとObjectクラスの関係はParentクラスを介して行われるため、コンストラクターが呼び出されます。 ObjectクラスのParentクラスのコンストラクターを呼び出す必要があります。