Java ポリモーフィズムはどのように実装されますか?
Java のポリモーフィズムは C++ と同じであり、遅延バインディングまたはランタイム バインディングを通じて実装されます。オブジェクトによって参照されるメソッドが呼び出されるとき、コンパイラは、その参照が変数の宣言時に指定された型オブジェクトを指しているのか、それともその型のサブクラスのオブジェクトを指しているのかを知りません。したがって、コンパイラはこの呼び出しの特定のメソッドにバインドできません。実行時に Java のランタイム型識別 (RTTI) を通じて特定のメソッドにのみバインドできます。以下は具体的な例です:
class shape { public void draw() { print("shape"); } } class triangle extends shape { public void draw() { print("triangle"); } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); s.draw(); }
その結果、triangle
s は形状参照ですが、実行時には三角形オブジェクトであるため、依然として三角形の描画メソッドが呼び出されます。
Java ポリモーフィズムのいくつかの落とし穴
プライベート メソッドをオーバーライドしますか?
プライベート メソッドは Java ではオーバーライドできません。プライベート メソッドはサブクラスでは表示されないため、これは簡単に理解できます。サブクラスは親クラスのプライベート メソッドを継承せず、ましてやオーバーライドすることもありません。したがって、サブクラス内の同名のメソッドは全く新しいメソッドとなります。
public class Polymorphism { private void show() { print("show parent"); } public static void main(String[] args) { Polymorphism p=new privateMethod(); p.show(); } } class privateMethod extends Polymorphism { public void show() { print("show derived"); } }
その結果、showparent
フィールドと静的メソッドの多態性が生じますか?
サブクラスは親クラスの非プライベートフィールドを継承できます。サブクラスのフィールドも多態的ですか?実際の例を見てみましょう:
class shape { protected int perimeter=1; public void draw() { print("shape"); } public int getPerimeter() { return perimeter; } } class triangle extends shape { int perimeter=3; public void draw() { print("triangle"); } public int getPerimeter() { return perimeter; } public int getSuperPerimeter() { return super.perimeter; } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); print("s.perimeter:"+s.perimeter); print("s.getperimeter:"+s.getPerimeter()); triangle t=new triangle(); print("t.perimeter:"+t.perimeter); print("t.getperimeter:"+t.getPerimeter()); print("t.getsuperperimeter:"+t.getSuperPerimeter()); } }
この演算結果には次の情報が含まれています:
1. 三角形オブジェクトが形状に変換された後、フィールドへの直接アクセスはコンパイラーによって決定されるため、ポリモーフィズムは表示されません。戻り値は1です。
2. 三角形オブジェクトが形状に変換された後、ランタイム オブジェクト タイプの遅延バインディングに基づいてフィールドにアクセスするメソッドが呼び出され、三角形の getperimeter メソッドが呼び出され、戻り値は 3 です。オブジェクトには 2 つの境界フィールドが含まれており、1 つは自分自身の中にあり、もう 1 つは親の種に由来しています。同時に、フィールド名を指定してフィールドを呼び出すと、デフォルトで独自の境界フィールドが返されます。親クラスから継承したフィールドを呼び出すには、super.perimeter メソッドを使用します。
この結果は少し混乱しているように思えます。この状況を回避するには、通常、フィールドをプライベートとして宣言します (サブクラスは継承できません)。同時に、サブクラスのフィールドとは異なるフィールドを宣言しないことが最善です。親クラスから継承されたフィールドは同じ名前を持ちます。
静的メソッドはクラスにバインドされており、特定の型が不明な状況がないため、静的メソッドにはポリモーフィズムがありません。
構築メソッド自体が静的メソッドであるため、コンストラクターはポリモーフィックではありません (そうでない場合、鶏が先か卵が先かというサイクルに陥ってしまいます)。問題を紹介するために、まずコンストラクターが呼び出される順序を見てみましょう。
1. このオブジェクトに割り当てられた記憶域は 0 に初期化されます (オブジェクトは null に初期化されます)
2. 親クラスのコンストラクターが呼び出されます (これにより、サブクラスのコンストラクターでアクセスされるフィールドが確実に初期化されます) 3. メンバー変数の初期化
4. サブクラスのコンストラクター呼び出し
次に、2 番目のステップで、親クラスのコンストラクター内のメソッドを呼び出すとします。このメソッドはポリモーフィックですか?具体的な例を見てみましょう:
class shape { protected int perimeter=1; public shape() { draw(); print("shape created"); } public void draw() { print("draw shape "+perimeter); } } class triangle extends shape { int perimeter=3; public triangle() { print("triangle created"); } public void draw() { print("draw triangle "+perimeter); } public int getPerimeter() { return perimeter; } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); } }
三角形オブジェクトはまだ構築されていませんが、描画メソッドは依然として三角形の描画メソッドに動的にバインドされていることがわかります。また、周囲の値が 3 ではなく 0 に初期化されていることにも注意してください。
その結果、初期化される前に三角形オブジェクト内のフィールドにアクセスすることになります。したがって、実際のアプリケーションでは、コンストラクター内で他のメソッドを呼び出さないようにするか、プライベートメソッドのみを呼び出す必要があります(継承されないため、この問題は発生しません)
Javaポリモーフィズムを使用する際の注意事項については、その他の記事を参照してください。 PHP中国語サイトへ!