Javaで継承を使用した際に、メソッドのオーバーライドやメソッド呼び出しがどのように動作するかを理解することは重要です。特に、親クラスと子クラスで同じメソッド名が存在する場合、そのメソッドがどのように呼ばれるかは、オブジェクトの型やメソッドの実装によって異なります。この記事では、オーバーライドに関する質問について解説します。
オーバーライドの基本
オーバーライド(Overriding)は、Javaにおいて親クラスのメソッドを子クラスで再定義することを指します。これにより、親クラスのメソッドの動作を変更することができます。オーバーライドされたメソッドは、親クラスではなく、子クラスの実装が使用されます。
オーバーライドは、メソッドのシグネチャ(戻り値の型、メソッド名、引数リスト)を親クラスのものと一致させて行われます。`@Override` アノテーションを使用することで、コンパイル時にオーバーライドの正当性をチェックすることができます。
質問のコードにおけるオーバーライドの挙動
質問のコードを見てみましょう。以下のようなコードが示されています。
class A {
public void sample() {}
}
class B extends A {
public void sample() {}
}
class C extends B {
public void sample() {}
}
class Main {
public static void main(String[] args) {
A a = new B();
a.sample();
}
}
ここでは、クラスA、B、Cがそれぞれ`sample()`メソッドを持ち、`B`は`A`を継承し、`C`は`B`を継承しています。`Main`クラスの`main`メソッドでは、`A`型の変数`a`が`B`型のインスタンスを参照し、`sample()`メソッドを呼び出しています。
呼ばれるメソッドはどれか?
このコードにおいて、`a.sample()`が呼び出された場合、実際に呼び出されるメソッドは、`B`クラスでオーバーライドされた`sample()`メソッドです。なぜなら、`a`は`A`型の変数でありながら、実際には`B`型のインスタンスを指しているため、Javaは実行時にオブジェクトの実際の型に基づいてメソッドを解決します。これを「動的バインディング」または「遅延バインディング」と呼びます。
したがって、`C`クラスの`sample()`メソッドは呼ばれません。この場合、`C`クラスでのオーバーライドは、`B`クラスの`sample()`メソッドを呼び出すコードに影響を与えません。
オーバーライドに関する注意点
オーバーライドを使用する際には、以下の点に注意が必要です。
- メソッドシグネチャの一致: 親クラスのメソッドと、子クラスのオーバーライドメソッドのシグネチャ(戻り値の型、メソッド名、引数の型と順序)は完全に一致する必要があります。
- アクセス修飾子: オーバーライドされたメソッドのアクセス修飾子は、親クラスのメソッドのアクセス修飾子と一致するか、より広いアクセス範囲に設定する必要があります。
- `super`の使用: 親クラスのメソッドを呼び出したい場合は、`super`キーワードを使用して明示的に親クラスのメソッドを呼び出すことができます。
まとめ
質問のコードにおいては、`a.sample()`を呼び出すと、`B`クラスの`sample()`メソッドが実行され、`C`クラスの`sample()`メソッドは呼ばれません。オーバーライドが適切に機能するためには、オーバーライドの対象となる親クラスのメソッドのシグネチャと一致する必要があります。
Javaでのメソッド呼び出しの挙動を理解することは、クラスの継承関係やポリモーフィズムを正しく活用するために非常に重要です。動的バインディングを活用して、柔軟で強力なオブジェクト指向プログラミングを実現しましょう。


コメント