何をするアノテーションか
@Override は「このメソッドは親のメソッドをオーバーライド(上書き)しています」とコンパイラに伝えるための印です。付けておくと、シグネチャの食い違いやタイプミス、オーバーロードとの取り違えなどをコンパイル時に検出できます。動作を変える魔法ではなく、間違いを“早期に”見つけるための強力な安全装置です。
どこで使えるかと基本ルール
クラスの継承でのオーバーライド
親クラスのメソッドを子クラスで置き換えるときに付けます。戻り値の共変(より具体的な型へ狭める)は許されますが、メソッド名・引数(型と並び)は親と一致している必要があります。
abstract class Shape {
abstract double area();
}
final class Rect extends Shape {
@Override
double area() { return w * h; } // 正しいオーバーライド
Rect(double w, double h) { this.w = w; this.h = h; }
private final double w, h;
}
Javaインターフェース実装にも使える
インターフェースのメソッドを実装する際も @Override を付けられます。default メソッドを上書きする場合も同様です。
interface Describable {
String describe();
}
final class User implements Describable {
@Override
public String describe() { return "User"; } // 実装に @Override を付ける
}
Java何が防げるのか(重要ポイントの深掘り)
オーバーライドのつもりが“オーバーロード”になる事故
引数や戻り値をうっかり変えてしまうと、同名の別メソッド(オーバーロード)になって、親のメソッドが呼ばれ続けます。@Override を付けていれば「親と一致していない」とコンパイルエラーになります。
class Base { void send(String s) {} }
class Sub extends Base {
// @Override を付けるとここはコンパイルエラー(引数型が違うため)
void send(Object o) {} // オーバーロードになってしまう
}
Javaタイプミスやアクセス修飾子の不一致
メソッド名のスペルミスや、親より狭いアクセス修飾子(public→protected など)への変更は、契約違反として検出されます。動作前に必ず止まるので安全です。
class Base { public void greet() {} }
class Sub extends Base {
@Override
protected void greet() {} // コンパイルエラー(公開範囲を狭められない)
}
Java例外宣言の広げすぎ
チェック例外(throws)の宣言を親より広げるのは不可。@Override を付けていれば、ここもコンパイル時に指摘されます。
付けても意味がない/付けられない場面
final・static・private メソッドは対象外
- final は上書き不可
- static はクラスメソッドで“隠蔽”になり、動的に切り替わらない
- private は外から見えないため、そもそもオーバーライドできない
これらに @Override を付けることはできません。
class Base {
final void lock() {}
static void util() {}
private void internal() {}
}
Java新規メソッドや間違ったシグネチャ
親に存在しないメソッドに @Override を付けると、即コンパイルエラーになります。これが「意図と実装のズレ」を抑止します。
super と合わせた典型パターン
親の処理を拡張する
親のメソッドに前後の処理を足したいとき、@Override と super の組み合わせが定番です。テンプレートメソッドやフック実装でよく使います。
class Base {
void render() { System.out.println("header"); }
}
class Sub extends Base {
@Override
void render() {
super.render(); // 親の前処理
System.out.println("body"); // 追加
}
}
Javaよくある混同と回避のコツ(重要ポイントの深掘り)
オーバーロードとの違いを固定する
「引数の違い=オーバーロード」「完全一致=オーバーライド」。迷ったら必ず @Override を付ける。コンパイラが“本当に上書きできているか”を保証してくれます。
戻り値の共変はOK、広げるのはNG
より具体的な型に狭める(Animal→Cat)は可。ただし、より広い型に変える(Cat→Animal)と互換性違反になります。
class Animal {}
class Cat extends Animal {}
class Factory { Animal create() { return new Animal(); } }
class CatFactory extends Factory {
@Override
Cat create() { return new Cat(); } // 共変戻り値(OK)
}
Javaインターフェース実装でも忘れない
インターフェースを実装するメソッドにも @Override を付ける習慣を徹底すると、タイポやシグネチャのズレを早期に検出できます(default メソッドの上書きも同様)。
例題で身につける
例 1: 正しいオーバーライドと誤りの差
abstract class Shape { abstract double area(); }
final class Circle extends Shape {
@Override
double area() { return Math.PI * r * r; } // OK
Circle(double r) { this.r = r; }
private final double r;
}
final class BadCircle extends Shape {
// @Override を付けるとコンパイルエラー(戻り値型が違う)
int area() { return (int)(Math.PI * r * r); } // 誤り:シグネチャ不一致
BadCircle(int r) { this.r = r; }
private final int r;
}
Java例 2: インターフェースの default を上書き
interface Describable {
default String describe() { return "unknown"; }
}
final class Product implements Describable {
@Override
public String describe() { return "Product"; } // default を上書き
}
Java例 3: 契約違反(公開範囲を狭める)
class Base {
public void run() {}
}
class Sub extends Base {
@Override
void run() {} // コンパイルエラー(public→package-privateへは狭められない)
}
Java仕上げのアドバイス(重要部分のまとめ)
@Override は「意図したオーバーライドが本当に成立しているか」を機械的に保証するためのマーカーです。常に付けて、オーバーロードとの取り違え・タイプミス・公開範囲や例外宣言の互換性違反をコンパイル時に潰しましょう。クラス継承でもインターフェース実装でも付ける習慣を徹底するだけで、ポリモーフィズムのバグが激減します。
