Javaは多くの場面で用いられるプログラミング言語です。便利な機能を持っているため、大規模開発でも使われるケースが多々あります。
しかし、正しく使わなければ、効率よくプログラミングを行えません。特にオーバーライドは使えると便利な機能ですが、使うには条件があります。
この記事では、Javaのオーバーライドについて、使い方や条件、注意点、できない条件など詳しく解説していきます。Javaのオーバーライドを知りたい方には必見の内容です。
ぜひ、最後までご覧いただき、Javaのオーバーライドについての理解を深めてください。
目次
1.Javaのオーバーライドとは
Javaのオーバーライドとは、親クラスで定義されたメソッドを、子クラスで再定義する仕組みです。同じメソッド名と引数を持ちながら、子クラス独自の振る舞いを実装できるため、継承関係を生かした柔軟なコードが実現できます。
例えば、AnimalクラスにmakeSound()メソッドを定義し、それを継承するDogクラスとCatクラスで異なる鳴き声を実装することで、共通のインターフェースを持ちながら個別の処理を行えます。
オーバーライドを正しく行うには、いくつかのルールを理解しておく必要があります。
具体的には、メソッド名・引数の型・戻り値の型を一致させること、アクセス修飾子の制約を守ること、@Overrideアノテーションを使用することなどが挙げられます。こうしたルールを踏まえることで、意図しないエラーを防ぎつつ、オブジェクト指向設計のメリットを最大限に活かせます。
2.Javaのオーバーライドを使う2つのメリット
Javaのオーバーライドを使うメリットは主に以下の2つです。理解を深めるためにもメリットはしっかりと把握しておくのがおすすめです。
再利用しやすい
保守しやすい
それぞれを解説していきます。
再利用しやすい
オーバーライドを活用すると、基本的なメソッドの定義を親クラスに集約し、子クラスごとに異なる振る舞いを実装できます。この仕組みを用いることで、コードの重複を避けつつ、柔軟に拡張できるようになります。
例えば、Vehicleクラスにmove()メソッドを定義し、CarやBicycleクラスでオーバーライドすると、それぞれの移動方法に応じた処理を記述できます。
加えて、変更が必要になった際にも、親クラスのメソッドを編集するだけで全ての子クラスに影響を与えられるため、メンテナンスの手間を軽減できます。結果、大規模なシステム開発においても、一貫性を保ちつつ効率的に機能追加が可能です。
保守しやすい
オーバーライドを適切に活用すると、コードの保守性が向上します。特に、親クラスに基本的なメソッドを定義し、子クラスごとに必要な部分だけをカスタマイズする設計は、後の修正や機能追加をスムーズにします。
例えば、ECサイトの決済処理を行うPaymentクラスを基盤とし、CreditCardPaymentやPayPalPaymentといった派生クラスでオーバーライドすれば、新しい決済方法を追加する際も他の処理に影響を与えずに拡張可能です。
また、@Overrideアノテーションを使用すると、意図しないメソッドの誤記やバグを防げます。オーバーライドのルールを理解し、適切に活用することで、保守性の高いコードを実現できます。
関連記事
Java初心者ガイド|Java学習のロードマップと効率良い勉強方法を解説
3.Javaのオーバーライドとオーバーロードの違い
Javaのオーバーライド(Override)とオーバーロード(Overload)は、どちらもメソッドを再定義する概念ですが、目的やルールが異なります。適切な場面で使い分けるためにも、違いを理解するようにしましょう。それぞれの違いは以下のとおりです。
項目 | オーバーライド | オーバーロード |
---|---|---|
対象 | 継承関係のある親クラスと子クラス | 同じクラス内 |
メソッド名 | 同じ | 同じ |
引数の数や型 | 同じ | 異なる |
返り値の型 | 同じ | 自由 |
アノテーション | @overrideの使用が推奨 | 不要 |
主にオーバーライドは「既存のメソッドを上書きする」目的、オーバーロードは「同じ名前で異なる処理を定義する」目的で使われます。それぞれの特徴を理解し、適切な設計を行うことが重要です。
4.Javaのオーバーライドの使い方や条件
Javaのオーバーライドの使い方や条件をそれぞれ解説していきます。
オーバーライドの基本的な使い方
オーバーライドは、親クラスのメソッドを子クラスで再定義することで、特定の動作を変更したり拡張したりする目的で使用されます。
例えば、Vehicleクラスのmove()メソッドをCarクラスでオーバーライドする場合、次のように記述します。
class Vehicle { void move() { System.out.println("Moving..."); } }
@Override void move() { System.out.println("Car is driving..."); } } |
この場合、Carクラスのmove()が呼び出されると、「Car is driving...」が出力されます。
オーバーライドの条件
オーバーライドを行う際には、以下のルールを守る必要があります。
ルール | 内容 |
---|---|
メソッド名・引数・戻り値の型を一致させる | 親クラスのメソッドと完全に同じシグネチャ(メソッド名+引数)で定義する必要がある。 ただし、戻り値の型は「共変戻り値」である場合、親クラスよりも具体的な型を指定できる。 |
アクセス修飾子の制限を守る | オーバーライドする際、親クラスのメソッドよりアクセスレベルを狭めることはできない。 例えば、publicなメソッドをprotectedやprivateに変更するとコンパイルエラーになる。 |
例外の制約を守る | オーバーライドされたメソッドは、親クラスのメソッドで宣言された例外を超える例外をスローすることはできない。 例えば、親クラスでthrows IOExceptionが定義されている場合、子クラスはIOExceptionまたはそのサブクラスの例外しかスローできない。 |
@Overrideアノテーションを使用する | @Overrideをつけることで、オーバーライドが正しく行われているかコンパイル時にチェックされる。 例えばメソッド名のスペルミスや引数の違いによる意図しないバグを防げる。 |
superキーワードの活用 | 親クラスのメソッドをオーバーライドしつつ、その元の処理も利用したい場合はsuperを使う。 |
関連記事
Javaプログラミングで何ができる?始め方や基本文法、練習サイト5つを紹介
5.Javaのオーバーライドの注意点・できない条件
Javaのオーバーライドを正しく活用するためには、以下の注意点に気をつける必要があります。
戻り値の型と引数
@Override(アノテーション)
static修飾子
アクセス修飾子
abstract修飾子
final修飾子
throwsでの例外クラスの指定
一つずつ解説していきます。
戻り値の型と引数
オーバーライドを行う場合、メソッド名と引数の型や数は完全に一致させる必要があります。引数の型や数を変更すると、オーバーロードと見なされるため注意が必要です。
ただし、戻り値の型は「共変戻り値」が許可されています。つまり、親クラスのメソッドが返す型のサブクラスを返す場合に限り、戻り値の型を変更できます。
例:共変戻り値の使用
class Parent { Parent create() { return new Parent(); } }
@Override Child create() { // 親クラスの戻り値よりも派生した型を返す return new Child(); } } |
この例では、親クラスの戻り値がParent型なら、子クラスではParentのサブクラスであるChild型を返せます。
@Override(アノテーション)
@Overrideアノテーションは、オーバーライドが正しく行われていることを保証するためのマーカーです。記述しなくてもプログラムは動作しますが、誤ったオーバーライドを防ぐために基本的に使用するのが推奨されます。
例:誤ったオーバーライドの書き方
class Parent { void display() {} }
void dispaly() {} // メソッド名のスペルミス } |
このコードでは、dispaly()というスペルミスがあるため、オーバーライドされず、新規メソッドとして定義されてしまいます。
例:正しいオーバーライドの書き方
class Child extends Parent { @Override void display() { // スペルミスがあればコンパイルエラーになる System.out.println("Overridden method"); } } |
このように、@Overrideを付けていればコンパイルエラーになり、ミスを発見しやすくなります。
static修飾子
オーバーライドは、インスタンスメソッド(非staticメソッド)に対して行われるため、staticメソッドはオーバーライドできません。
もしstaticメソッドを子クラスで同じ名前で再定義した場合、それは「オーバーライドではなく、単なるメソッドの隠蔽」となります。
例:static修飾子を使ってオーバーライドできなかった
class Parent { static void show() { System.out.println("Parent"); } }
static void show() { // オーバーライドではなく、隠蔽 System.out.println("Child"); } } |
アクセス修飾子
オーバーライドするメソッドのアクセス修飾子は、親クラスより狭くはできません。ただし、より広いアクセスレベルに変更することは可能です。
親クラスのアクセス修飾子 | 子クラスで許可されるアクセス修飾子 |
---|---|
private | オーバーライド不可 |
デフォルト | デフォルト, protected, public |
protected | protected, public |
public | 変更不可 |
abstract修飾子
abstractメソッドは、サブクラスで必ずオーバーライドしなければならないメソッドです。オーバーライドしないと、サブクラスもabstractクラスとして定義する必要があります。
abstract class Animal { abstract void makeSound(); }
@Override void makeSound() { System.out.println("Bark"); } } |
ここで、makeSound()をオーバーライドしないと、Dogクラスもabstractにする必要があります。
final修飾子
finalが付いたメソッドは、オーバーライドできません。親クラスでオーバーライドを防ぎたい場合に使用します。
class Parent { final void show() { System.out.println("This cannot be overridden"); } }
// @Override // void show() {} // コンパイルエラー } |
この場合、show()メソッドは親クラスでfinalが付いているため、子クラスでオーバーライドできません。
throwsでの例外クラスの指定
オーバーライドしたメソッドは、親クラスのメソッドより広い例外をスローできません。ただし、親クラスがスローする例外のサブクラスの例外を指定することは可能です。
エラー例:より広い例外をスローするとエラー
class Parent { void process() throws IOException {} }
// void process() throws Exception {} // コンパイルエラー } |
OK例:サブクラスの例外をスロー
class Child extends Parent { @Override void process() throws FileNotFoundException {} // IOExceptionのサブクラスならOK } |
6.まとめ
今回は、Javaのオーバーライドについて、使い方やメリット、注意点、できない条件などをお話ししました。
Javaは大規模開発がしやすい仕組みがあるため、利用されるシーンも多くなっています。しかし、正しい使い方を行わないと思ったような結果が得られません。オーバーライドを上手く利用して、効率よく開発を行いましょう。
最後までお読みいただきありがとうございました。
本記事が皆様にとって少しでもお役に立てますと幸いです。