Java オーバーライド(Override)とオーバーロード(Overload)


オーバーライド(Override)

オーバーライド(Override)とは、サブクラスが親クラスと同じ名前、引数リスト、戻り値の型を持つメソッドを定義し、サブクラスのメソッド実装が親クラスのメソッド実装を上書きすることを指します。つまり、外枠は不変で、中身を書き換える!

オーバーライドの利点は、サブクラスが必要に応じて自分自身に固有の動作を定義できることです。つまり、サブクラスは必要に応じて親クラスのメソッドを実装できます。これにより、サブクラスのオブジェクトを使ってそのメソッドを呼び出すと、親クラスのメソッドではなくサブクラスのメソッドが実行されます。

オーバーライドするメソッドは、新しいチェック例外や、オーバーライドされるメソッドが宣言するより広いチェック例外をスローすることはできません。例:親クラスのメソッドがチェック例外 IOException を宣言している場合、このメソッドをオーバーライドするときに Exception 例外をスローすることはできません。Exception は IOException の親クラスだからです。IOException 例外または IOException のサブクラスの例外をスローします。

オブジェクト指向の原則では、オーバーライドは既存のメソッドを書き換えられることを意味します。例は次のとおりです。

TestDog.java ファイルコード:

class Animal{ public void move(){ System.out.println("動物は移動できます"); } } class Dog extends Animal{ public void move(){ System.out.println("犬は走ることと歩くことができます"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); //Animal オブジェクト Animal b = new Dog(); //Dog オブジェクト a.move();//Animal クラスのメソッドを実行 b.move();//Dog クラスのメソッドを実行 } }

上記の例のコンパイル・実行結果は次のとおりです。

動物は移動できる
犬は走ったり歩いたりできる

上記の例では、b は Animal 型ですが、実行されるのは Dog クラスの move メソッドです。

これは、コンパイル段階ではパラメータの参照型だけがチェックされるためです。

しかし実行時には、Java仮想マシン(JVM)がオブジェクトの型を特定し、そのオブジェクトのメソッドを実行します。

したがって、上記の例でコンパイルが成功するのは、Animal クラスに move メソッドが存在するためであり、実行時には特定のオブジェクトのメソッドが実行されます。

次の例を考えてみましょう:

TestDog.java ファイルコード:

class Animal{ public void move(){ System.out.println("動物は移動できます"); } } class Dog extends Animal{ public void move(){ System.out.println("犬は走ることと歩くことができます"); } public void bark(){ System.out.println("犬は吠えることができます"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); //Animal オブジェクト Animal b = new Dog(); //Dog オブジェクト a.move();//Animal クラスのメソッドを実行 b.move();//Dog クラスのメソッドを実行 b.bark(); } }

上記の例のコンパイル・実行結果は次のとおりです。

TestDog.java:30: cannot find symbol
symbol  : method bark()
location: class Animal
                b.bark();
                 ^

このプログラムはコンパイルエラーをスローします。b の参照型 Animal には bark メソッドがないためです。


メソッドのオーバーライド規則

  • パラメータリストは、オーバーライドされるメソッドのパラメータリストと完全に同じでなければなりません。

  • 戻り値の型は、オーバーライドされるメソッドの戻り値の型と異なっていても構いませんが、親クラスの戻り値の派生クラスである必要があります(Java 5 以前では戻り値の型を同じにする必要があり、Java 7 以降では異なっていても構いません)。

  • アクセス修飾子は、親クラスでオーバーライドされるメソッドのアクセス権限よりも低くすることはできません。例:親クラスのメソッドが public と宣言されている場合、サブクラスでそのメソッドをオーバーライドするときは protected と宣言できません。

  • 親クラスのメンバーメソッドは、そのサブクラスによってのみオーバーライドできます。

  • final と宣言されたメソッドはオーバーライドできません。

  • static と宣言されたメソッドはオーバーライドできませんが、再宣言することはできます。

  • サブクラスと親クラスが同じパッケージにある場合、サブクラスは private と final と宣言されたメソッドを除く、親クラスのすべてのメソッドをオーバーライドできます。

  • サブクラスと親クラスが同じパッケージにない場合、サブクラスは親クラスの public および protected と宣言された非 final メソッドのみをオーバーライドできます。

  • オーバーライドするメソッドは、オーバーライドされるメソッドが例外をスローするかどうかに関係なく、任意の非チェック例外をスローできます。ただし、オーバーライドするメソッドは、新しいチェック例外や、オーバーライドされるメソッドが宣言するものより広いチェック例外をスローすることはできません。逆の場合は可能です。

  • コンストラクタはオーバーライドできません。

  • クラスを継承できない場合、そのクラスのメソッドをオーバーライドすることはできません。


Super キーワードの使用

サブクラスで親クラスのオーバーライドされたメソッドを呼び出す必要がある場合は、super キーワードを使用します。

TestDog.java ファイルコード:

class Animal{ public void move(){ System.out.println("動物は移動できます"); } } class Dog extends Animal{ public void move(){ super.move(); //superクラスのメソッドを使用 System.out.println("犬は走ることと歩くことができます"); } } public class TestDog{ public static void main(String args[]){ Animal b = new Dog(); //Dog オブジェクト b.move(); //Dog クラスのメソッドを実行 } }

上記の例のコンパイル・実行結果は次のとおりです。

動物は移動できる
犬は走ったり歩いたりできる

オーバーロード(Overload)

オーバーロード(overloading) とは、1つのクラス内で、メソッド名が同じで、パラメータが異なることを指します。戻り値の型は同じでも異なっていても構いません。

オーバーロードされた各メソッド(またはコンストラクタ)は、一意のパラメータ型リストを持たなければなりません。

最も一般的な使用例はコンストラクタのオーバーロードです。

オーバーロードの規則:

  • オーバーロードされるメソッドはパラメータリストを変更しなければなりません(パラメータの数または型が異なること)。
  • オーバーロードされるメソッドは戻り値の型を変更できます。
  • オーバーロードされるメソッドはアクセス修飾子を変更できます。
  • オーバーロードされるメソッドは、新しいまたはより広いチェック例外を宣言できます。
  • メソッドは同じクラス内またはサブクラス内でオーバーロードできます。
  • 戻り値の型をオーバーロード関数の区別基準にすることはできません。

例

Overloading.java ファイルコード:

public class Overloading { public int test(){ System.out.println("test1"); return 1; } public void test(int a){ System.out.println("test2"); } //次の2つはパラメータの型の順序が異なります public String test(int a,String s){ System.out.println("test3"); return "returntest3"; } public String test(String s,int a){ System.out.println("test4"); return "returntest4"; } public static void main(String[] args){ Overloading o = new Overloading(); System.out.println(o.test()); o.test(1); System.out.println(o.test(1,"test3")); System.out.println(o.test("test4",1)); } }

オーバーライドとオーバーロードの違い

相違点 オーバーロードメソッド オーバーライドメソッド
パラメータリスト 変更必須 変更してはならない
戻り値の型 変更可 変更してはならない
例外 変更可 削減または削除できる。新しいまたはより広い例外をスローしてはならない
アクセス 変更可 より厳しい制限を加えてはならない(制限を緩めることはできる)

まとめ

メソッドのオーバーライド(Overriding)とオーバーロード(Overloading)は、Javaのポリモーフィズムの異なる表現です。オーバーライドは親クラスとサブクラス間のポリモーフィズムの1つの表現であり、オーバーロードはポリモーフィズムの具体的な表現形式と理解できます。

  • (1) メソッドのオーバーロードとは、1つのクラス内に同じメソッド名を持つ複数のメソッドが定義されており、それらのパラメータの数が異なる、または数が同じでも型と順序が異なる場合、メソッドのオーバーロード(Overloading)と呼ばれます。
  • (2) メソッドのオーバーライドとは、サブクラスに親クラスのメソッドと同じ名前、同じパラメータの数と型、同じ戻り値を持つメソッドが存在する場合、そのメソッドをオーバーライド(Overriding)と呼びます。
  • (3) メソッドのオーバーロードは1つのクラスのポリモーフィズムの表現であり、メソッドのオーバーライドはサブクラスと親クラス間のポリモーフィズムの表現です。

その他の拡張