私は2つのクラスを考えてみましょうA
とB
。B
継承A
し、B
次のメソッドがあります。
public boolean equals(Object other) {
System.out.print("Object");
return true;
}
public boolean equals(A other){
System.out.print("A object");
return true;
}
public boolean equals(B other) {
System.out.print("B object");
return true;
}
A a1 = new A();
A ab = new B();
B b1 = new B();
どのような私には不明であることは、なぜです
ab.equals(a1)
ab.equals(b1)
戻り値 Object
ab
インスタンスB
のポインタでA
。a1
明らかに両方のインスタンスのポインタですA
。だから、なぜそれが使用しないObject other
代わりのA other
方法を?同じことがのために行くb1
のインスタンスであるB
ポアントとB
、まだ私は通常のオブジェクトを挿入するようにコンパイラに等しい方法を適用することを選びました?AM私は愚かか、この言語の支離滅裂ですか?
ところでA
どんなれていないequals
すべてのメソッドを。
説明
ところで
A
どんなれていないequals
すべてのメソッドを。
しかし、あなたは行います
ab.equals(a1)
ab.equals(b1)
そして、ab
次のとおりです。
A ab = new B();
それは実際にいる間のでB
、変数は型ですA
。
このような状況での方法を選択するためのJavasルールを探し始めますequals
のメソッドA
クラス。そして、それは実際には1つ、から継承されたデフォルトの実装を持っていますObject
。これは、署名を持っています
public boolean equals(Object other)
だから、この署名を決定します。今では、実際のインスタンスの後ろに尋ねるab
タイプのもので、B
その署名と方法のために、。それはでオーバーライドされた実装を選択しますB
:
public boolean equals(Object other) {
System.out.print("Object");
}
そして、結果的に印刷しObject
、両方のケースで。
細部
このため詳細はで定義されていJLS§15.12。メソッド呼び出し式。それは見つけることについて語っ最も具体的な一致を。あなたは深いそれに飛び込む場合のルールは非常に複雑に得ることができます。
いくつか抜粋:
コンパイル時にメソッド呼び出しを処理するための最初のステップは、クラスまたはインタフェースその名前のメソッドの定義を検索するために呼び出されるメソッドの名前とを把握することです。
第二のステップは、メンバメソッドの前のステップで決定されたタイプを検索します。このステップは、正確に与えられた引数で呼び出すことができ宣言の両方にアクセス可能と適用可能な方法を、見つけるためにメソッドの名前と引数式を使用しています。
最も特定のいずれかが選択される場合には、複数のそのような方法が存在してもよいです。最も具体的な方法の記述(署名プラス戻り値の型)は、メソッドのディスパッチを実行するために、実行時に使用されるものです。
コンパイル時間ステップ1(§15.12.1)によって決定されるクラスまたはインタフェースがそのメソッド呼出しに潜在的に適用されるすべてのメンバ・メソッドを探索します。スーパークラスやスーパーインタフェースから継承されたメンバーは、この検索に含まれています。
複数のメンバメソッドは、メソッドの呼び出しにアクセスし、該当の両方である場合、実行時のメソッドディスパッチのための記述を提供するために、いずれかを選択する必要があります。Javaプログラミング言語は、最も具体的な方法が選択されていることをルールを使用しています。