PR

Java:オーバーライドの基本と注意点を3分で整理

Java

オーバーライド(Override) とは、継承やインターフェース実装によって引き継いだメソッドの実装を、子クラスや実装クラスで再定義することを指します。

  • ポイント
    • オーバーライドするメソッド名・引数リスト・戻り値の型は、親クラスやインターフェースで定義されたメソッドと完全に一致している必要があります(Java 5以降は、戻り値の型の共変戻り値型(Covariant Return Types)を一部許容する仕様がありますが、基本的には整合が必要です)。
    • オーバーライド先のアクセス修飾子は、元のメソッドより狭くしてはいけません。例)親メソッドが public なら、子メソッドを protectedprivate にはできません。

参考 クラスの継承 / インターフェース

スポンサーリンク

オーバーライドの基本知識

オーバーライドの定義

  • オーバーライド(Override) とは、継承やインターフェース実装によって引き継いだメソッドの実装を、子クラスや実装クラスで再定義することを指します。

オーバーライドの意義

  • 親クラス(スーパークラス)やインターフェースで宣言・定義されているメソッドを子クラス(サブクラス)や実装クラスで上書き(override) できることで、同じメソッド呼び出しでも違う処理を行う可能性が生まれます。
  • 多態性(ポリモーフィズム) の実現における重要な仕組みの一つです。

注意点:同名メソッドとの違い

  • 同じクラス内でたとえメソッド名が同じであっても、継承関係が存在しなければオーバーライドではなく、単に別のメソッドです(オーバーロードは後述)。

なぜオーバーライドが必要か?

柔軟な実装を可能にする

例えば、親クラス側の実装では一般的な処理を定義し、子クラスではそれを上書きしてより専門的な振る舞いに変えることができます。これによって、共通部分は親クラスにまとめつつ、個別のクラスで挙動を変えるという柔軟性が得られます。

class Animal {
    void makeSound() {
        System.out.println("Some generic animal sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark!");
    }
}

実装の共通化と差異化

インターフェースを実装するクラスでも、オーバーライドによって実装の“違い”を生み出せます。複数のクラスが同一インターフェースを実装していても、各クラスで処理を異なる形で提供できるため、コードの共通化差異化を両立できます。

interface Greeting {
    void sayHello();
}

class EnglishGreeting implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("Hello");
    }
}

class JapaneseGreeting implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("こんにちは");
    }
}

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

  • オーバーライド(Override)
    • 継承元のメソッドを、シグニチャ(メソッド名、引数リスト、戻り値の型)を同じにして再定義すること。
    • ポイント:継承やインターフェースの実装が前提。
  • オーバーロード(Overload)
    • 同じクラス内で、メソッド名は同じだが引数リストが異なるメソッドを定義すること。
    • 例:void doSomething(), void doSomething(String param), int doSomething(int x, int y) など。
    • ポイント:引数の数や型が違うことでメソッドを複数定義する手法。

名前が似ているので混同しがちですが、継承またはインターフェースの実装が絡む場合はオーバーライド単純に同じクラス内などで引数違いのメソッドを用意する場合はオーバーロードと把握すると明確になります。

オーバーライド時の注意点

  1. シグニチャの一致
    • メソッド名、引数の個数と型、戻り値の型が同じであることが必要です。
    • ただし、Java 5 以降では共変戻り値型(親のメソッドの戻り値が Animal なら、子のメソッドの戻り値を Dog にするなど)を許容しています。
  2. アクセス修飾子の制約
    • オーバーライド先(子クラス側)のアクセス修飾子を、元のメソッドより狭めることはできません。
    • 親が public → 子も public (もしくは同等)
    • 親が protected → 子は protectedpublic
    • 親が private はそもそもオーバーライドできません(継承先から見えないため)。
  3. 例外宣言の制約
    • チェック例外をスローする場合、オーバーライドメソッドで宣言する例外は、親のメソッドが宣言する例外と同じまたはそのサブクラスでなければなりません。
    • 例外の数や種類を追加して広げることはできません。
  4. @Override アノテーションの活用
    • オーバーライドするメソッドには、明示的に @Override アノテーションを付けるのが一般的です。
    • 付けることで、コンパイラが「これは正しいオーバーライドか」をチェックしてくれます。
class Parent {
    void show() {}
}

class Child extends Parent {
    @Override
    void show() {
        // 再定義した処理
    }
}

実際の例を見てみよう

クラスの継承によるオーバーライド

class Vehicle {
    void run() {
        System.out.println("The vehicle is running.");
    }
}

class Car extends Vehicle {
    @Override
    void run() {
        System.out.println("The car is running fast!");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle myCar = new Car();
        myCar.run();  
        // 出力: "The car is running fast!"
    }
}
  • 親クラス Vehiclerun() メソッドを、子クラス Car で再定義している例です。
  • @Override を付けることで、オーバーライドであることが明示されます(省略した場合も動作しますが、付けたほうがエラーに気付きやすくなるので推奨されます)。

インターフェースの実装によるオーバーライド

interface Printable {
    void print();
}

class Book implements Printable {
    @Override
    public void print() {
        System.out.println("Printing a book...");
    }
}

public class Main {
    public static void main(String[] args) {
        Printable p = new Book();
        p.print();  
        // 出力: "Printing a book..."
    }
}
  • インターフェース Printable が定義しているメソッド print() を、クラス Book において実装している例です。
  • インターフェースのメソッドはデフォルトで public なので、実装する側も public でなければコンパイルエラーになります。

まとめ オーバーライドとは?

  • オーバーライド(Override) は、親クラス(あるいはインターフェース)のメソッドを、子クラス(あるいは実装クラス)側で再定義することを指します。
  • オーバーロード(Overload) は、同じクラス内で、メソッド名は同じだが引数リストが異なるメソッドを複数定義することを指します。オーバーライドとは別の概念なので混同しないように注意しましょう。
  • オーバーライド時は、シグニチャが一致しているか、アクセス修飾子例外宣言などの制約に違反していないかを確認してください。
  • @Override アノテーションを使うことで、コンパイルレベルでのエラー検知や可読性向上につながります。
タイトルとURLをコピーしました