Javaメソッドオーバーライド: スーパークラスの振る舞いをカスタマイズ
前章ではスーパークラスとサブクラスについて説明しました。クラスがスーパークラスからメソッドを継承する場合、そのメソッドがfinalでマークされていなければオーバーライドする機会があります。
オーバーライドの利点は:サブクラスタイプに固有の振る舞いを定義できることです。つまり、サブクラスは親クラスのメソッドを自身の要件に基づいて実装できます。
オブジェクト指向の用語では、オーバーライドとは既存メソッドの機能を上書きすることを意味します。
例
例を見てみましょう。
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal参照とAnimalオブジェクト
Animal b = new Dog(); // Animal参照だがDogオブジェクト
a.move(); // Animalクラスのメソッドが実行
b.move(); // Dogクラスのメソッドが実行
}
}
出力
Animals can move
Dogs can walk and run
上記例では、bがAnimal型であってもDogクラスのmoveメソッドが実行されます。理由は:コンパイル時には参照型でチェックが行われますが、実行時にはJVMがオブジェクト型を特定し、その特定のオブジェクトに属するメソッドを実行するためです。
したがって、上記例ではAnimalクラスにmoveメソッドがあるためプログラムは正常にコンパイルされます。そして実行時に、そのオブジェクト固有のメソッドが実行されます。
以下の例を考えてみてください。
例: コンパイルエラーになるケース
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal参照とAnimalオブジェクト
Animal b = new Dog(); // Animal参照だがDogオブジェクト
a.move(); // Animalクラスのメソッドが実行
b.move(); // Dogクラスのメソッドが実行
b.bark(); // コンパイルエラー!
}
}
出力
TestDog.java:26: error: cannot find symbol
b.bark();
^
symbol: method bark()
location: variable b of type Animal
1 error
このプログラムはコンパイル時エラーをスローします。なぜならbの参照型であるAnimalにbarkという名前のメソッドがないためです。
メソッドオーバーライドのルール
- 引数リストはオーバーライドされるメソッドとまったく同じでなければならない。
- 戻り値の型は、スーパークラスで宣言された元のオーバーライドメソッドの戻り値の型と同じか、そのサブタイプでなければならない。
- アクセスレベルは、オーバーライドされるメソッドのアクセスレベルより制限的であってはならない。例:スーパークラスのメソッドが
publicで宣言されている場合、サブクラスのオーバーライドメソッドをprivateやprotectedにすることはできない。 - インスタンスメソッドは、サブクラスによって継承されている場合のみオーバーライドできる。
finalで宣言されたメソッドはオーバーライドできない。staticで宣言されたメソッドはオーバーライドできないが、再宣言は可能。- メソッドが継承できない場合、オーバーライドできない。
- インスタンスのスーパークラスと同じパッケージ内のサブクラスは、
privateまたはfinalで宣言されていないスーパークラスのメソッドをオーバーライドできる。 - 異なるパッケージのサブクラスは、
publicまたはprotectedで宣言されておりfinalでないメソッドのみオーバーライドできる。 - オーバーライドメソッドは、オーバーライドされるメソッドが例外をスローするかどうかに関わらず、任意の非チェック例外をスローできる。しかし、オーバーライドメソッドは、オーバーライドされるメソッドで宣言されているものより新しい、またはより広範なチェック例外をスローしてはならない。オーバーライドメソッドは、オーバーライドされるメソッドより狭い、または少ない例外をスローできる。
- コンストラクタはオーバーライドできない。
superキーワードの使用
オーバーライドされたメソッドのスーパークラスバージョンを呼び出すときにsuperキーワードを使用します。
例
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
super.move(); // スーパークラスのメソッドを呼び出し
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal b = new Dog(); // Animal参照だがDogオブジェクト
b.move(); // Dogクラスのメソッドが実行
}
}
出力
Animals can move
Dogs can walk and run
Java
- Java演算子をマスター:種類、構文、実践例
- Javaインターフェース完全ガイド:概念、実装、ベストプラクティス
- Javaのtry-with-resourcesをマスターする:自動リソース管理の仕組みと活用法
- Java String.length()メソッド:文字列サイズ取得の実例解説
- Java String.indexOf()マスター:部分文字列検索と実践例
- Java String.charAt()完全解説:構文、戻り値、例外、実例
- Java String.compareTo()マスター:構文、ユースケース、実践例
- Java String.contains()メソッド:部分文字列チェックの実践例
- Java String.endsWith()マスター:文字列サフィックスチェック実例付き
- Java文字列置換マスター:replace()、replaceAll()、replaceFirst()徹底解説
- Java static 完全解説:変数・メソッド・ブロックの実践例