【Java】レッスン5-6:メソッドのオーバーライドを理解しよう

ながみえ

一つ前のページではクラスの継承について学習しました。

今回は メソッドのオーバーライド について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:メソッド編
Lesson4:コレクション編
Lesson5:クラス

 ・Lesson5-1:クラスの基本を確認しよう
 ・Lesson5-2:コンストラクタを理解しよう
 ・Lesson5-3:カプセル化を理解しよう
 ・Lesson5-4:クラスメンバとインスタンスメンバを理解しよう
 ・Lesson5-5:クラスの継承を理解しよう
 ・Lesson5-6:メソッドのオーバーライドを理解しよう ◁今回はココ
 ・Lesson5-7:抽象クラスを理解しよう
 ・Lesson5-8:インターフェースを理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:モンスターとのバトルゲームを作ろう
 ・確認問題5-☆3:マルバツゲーム(Tic-Tac-Toe)を作成しよう

<<前のページ

学習記事一覧

次のページ>>

オーバーライドの基礎|定義・書き方・注意点

オーバーライド(Override)とは、親クラスから継承したメソッドの処理内容を、子クラスで再定義して上書きする機能です。

これを使うことで、共通のメソッド名を持ちながら、クラスごとに異なる振る舞いを実現できます。

この知識を身につけることで、継承を活かした柔軟なクラス設計ができるようになり、ポリモーフィズムを使った拡張性の高いプログラムが書けるようになります。

それでは、オーバーライドの基本構文から実践的な使い方まで、順を追って見ていきましょう。

メソッドオーバーライドとは|定義と基本的な書き方

オーバーライド は、親クラスに定義されたメソッドと同じ名前、引数、戻り値を持つメソッドを子クラスで再定義することを指します。

このとき、メソッド名、引数の数と型、戻り値の型は親クラスと子クラスとで一致している必要があります。

また親クラスのメソッドに @Overrideアノテーション を追加すると、オーバーライドであることが明示され、エラーが検出しやすくなります。

オーバーライドの基本的な書き方は以下の通りです。

class 親クラス名 {
    void メソッド名() {
        // 処理内容
    }
}
class 子クラス名 extends 親クラス名 {
    @Override	//Overrideアノテーション
    void メソッド名() {	//親クラスと同じ名前のメソッド
        // 処理内容
    }
}

オーバーライドの例|継承を活かしたコード実装

オーバーライドはクラスの継承を前提とした技術です。

親クラスのメソッドをそのまま利用するだけでなく、子クラス独自の動作を追加したい場合に役立ちます。

たとえば動物クラスに定義された「鳴く」メソッドを、犬や猫といった子クラスでオーバーライドすることで、それぞれの動物に応じた鳴き声を出すように変更することができます。

class Animal {			// 親クラスの定義
    void makeSound() {	// makeSoundメソッドの定義
        System.out.println("Some generic animal sound");
    }
}
class Dog extends Animal {	// Animalクラスを継承したDogクラスの定義
    @Override				//Overrideアノテーション
    void makeSound() {		// 親クラスと同じ名前のメソッド
        System.out.println("Woof");
    }
}
class Cat extends Animal {	// Animalクラスを継承したCatクラスの定義
    @Override				//Overrideアノテーション
    void makeSound() {		//親クラスと同じ名前のメソッド
        System.out.println("Meow");
    }
}
class Main {	// メインクラス
    public static void main(String[] args) {
        Dog animal_1 = new Dog();	// インスタンス生成
        Cat animal_2 = new Cat();	// インスタンス生成

        animal_1.makeSound();	// 出力: Woof
        animal_2.makeSound();	// 出力: Meow
    }
}

この例ではAnimalクラスを継承したDogCatクラスが、それぞれの動物の鳴き声を出すようにmakeSoundメソッドをオーバーライドしています。

これによりDogオブジェクトのmakeSoundメソッドを呼び出すと「Woof」、CatオブジェクトのmakeSoundメソッドを呼び出すと「Meow」と表示されます。

これにより動物ごとに異なる鳴き声を表現でき、オブジェクト指向の多態性(ポリモーフィズム)が実現されます。

メソッドオーバーライドの注意点|アクセス修飾子と例外処理

オーバーライドにはいくつかのルールがあります。

オーバーライドするメソッドは、親クラスのメソッドと同じかそれより広いアクセス修飾子である必要があります。

たとえば親クラスでprotectedと指定されている場合、オーバーライドする子クラスのメソッドはprotectedまたはpublicである必要があります。privatefinalで宣言されたメソッドはオーバーライドできないため注意が必要です。

また例外についてもルールがあります。

親クラスのメソッドが特定の例外をスローする場合、子クラスのオーバーライドメソッドは同じ例外か、それよりも狭い範囲の例外をスローする必要があります。

まとめ|オーバーライドで継承をより柔軟に活かそう

オーバーライドは、親クラスから継承したメソッドを子クラスで再定義し、振る舞いを変更できる仕組みです。

本記事では基本的な書き方から、アクセス修飾子や例外の扱いに関する注意点まで学びました。

これにより、継承を活かしてクラスごとに柔軟な動作を実装する力が身についたはずです。

オーバーライドは、ポリモーフィズムやオブジェクト指向設計を実践する上で欠かせないスキルです。

今回の学習を土台に、さらに表現力のあるプログラム作りに挑戦してみましょう。

練習問題|メソッドのオーバーライドで動物ごとの鳴き声を表示しよう

動物の鳴き声を表示するプログラムを作成しましょう。

このプログラムでは動物の基本的な鳴き声を表示する「動物クラス」と、それを継承して「犬クラス」を作成します。

犬クラスではメソッドのオーバーライドを使って、犬が鳴くときの特有の鳴き声を表示します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. Animalクラスを作成し、soundメソッドを定義すること。
    • soundメソッドは「動物は音を出します」と表示すること。
  2. Animalクラスを継承したDogクラスを作成し、soundメソッドをオーバーライドすること。
    • オーバーライドしたsoundメソッドでは「犬は「ワンワン」と鳴きます」と表示すること。
  3. Mainクラス内で以下の処理を行うこと。
    • Animalクラスのインスタンスを作成し、soundメソッドを呼び出すこと。
    • Dogクラスのインスタンスを作成し、soundメソッドを呼び出すこと。

ただし、以下のような実行結果となること。

動物は音を出します
犬は「ワンワン」と鳴きます

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:Animalクラスの定義
  □ soundメソッドの定義
  □ □ 「動物は音を出します」と出力する

2:Dogクラスの定義(Animalクラスを継承)
  □ soundメソッドのオーバーライド
  □ □ 「犬は「ワンワン」と鳴きます」と出力する

3:Mainクラスの定義
  □ mainメソッドの定義
  □ □ AnimalクラスのインスタンスgenericAnimalを作成
  □ □ genericAnimalのsoundメソッドを呼び出す
  □ □ DogクラスのインスタンスmyDogを作成
  □ □ myDogのsoundメソッドを呼び出す

Q
ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

// 親クラス:動物(Animal)
class Animal {
    // 動物の鳴き声を表示するメソッド
    public void sound() {
        System.out.println("動物は音を出します");
    }
}

// 子クラス:犬(Dog) - Animalクラスを継承
class Dog extends Animal {
    /* 【穴埋め問題1】
       ここにsoundメソッドをオーバーライドし、「犬は「ワンワン」と鳴きます」と表示するコードを書いてください。
    */
}

// メインクラス
public class Main {
    public static void main(String[] args) {
        /* 【穴埋め問題2】
           ここにAnimalクラスのインスタンスgenericAnimalを作成し、soundメソッドを呼び出すコードを書いてください。
           出力は「動物は音を出します」となります。
        */
        
        /* 【穴埋め問題3】
           ここにDogクラスのインスタンスmyDogを作成し、soundメソッドを呼び出すコードを書いてください。
           出力は「犬は「ワンワン」と鳴きます」となります。
        */
    }
}

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

練習問題の解答と解説

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
// 親クラス:動物(Animal)
class Animal {
    // 動物の鳴き声を表示するメソッド
    public void sound() {
        System.out.println("動物は音を出します");
    }
}

// 子クラス:犬(Dog) - Animalクラスを継承
class Dog extends Animal {
    // soundメソッドをオーバーライドして、犬特有の鳴き声を表示する
    @Override
    public void sound() {
        System.out.println("犬は「ワンワン」と鳴きます");
    }
}

// メインクラス
public class Main {
    public static void main(String[] args) {
        // Animalクラスのインスタンスを作成してsoundメソッドを呼び出す
        Animal genericAnimal = new Animal();
        genericAnimal.sound(); // 出力:動物は音を出します
        
        // Dogクラスのインスタンスを作成してsoundメソッドを呼び出す
        Dog myDog = new Dog();
        myDog.sound(); // 出力:犬は「ワンワン」と鳴きます
    }
}
Q
正解コードの解説

コードをブロックごとに分割して解説します。

親クラス:Animal

class Animal {
    // 動物の鳴き声を表示するメソッド
    public void sound() {
        System.out.println("動物は音を出します");
    }
}

Animal クラスは基本的な動物の機能を持つ親クラスです。

sound メソッドには「動物は音を出します」と表示するコードが含まれており、動物全般の鳴き声を表現しています。

子クラス:Dog

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("犬は「ワンワン」と鳴きます");
    }
}

Dog クラスは Animal クラスを継承しており、動物の一種である「犬」を表しています。

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

@Override は、Animal クラスの sound メソッドを Dog クラス独自の実装に書き換えていることを示しています。

オーバーライド(上書き)によって、Dog クラスの sound メソッドを呼び出すと「犬は「ワンワン」と鳴きます」と表示され、犬特有の鳴き声が表現されるようになります。

オーバーライドすることで、親クラスから継承したメソッドを子クラスの要件に合わせてカスタマイズすることができます。

メインクラス:Main

public class Main {
    public static void main(String[] args) {
        Animal genericAnimal = new Animal();
        genericAnimal.sound(); // 出力:動物は音を出します

        Dog myDog = new Dog();
        myDog.sound(); // 出力:犬は「ワンワン」と鳴きます
    }
}

Main クラスには main メソッドがあり、プログラムの実行がここから始まります。

このメソッドの役割はAnimal クラスと Dog クラスのインスタンスを作成し、それぞれの sound メソッドを呼び出すことです。

インスタンスの生成とメソッドの呼び出し
  • genericAnimalAnimal クラスのインスタンスで、sound メソッドを呼び出すと「動物は音を出します」が表示されます。
  • myDogDog クラスのインスタンスで、sound メソッドを呼び出すと「犬は「ワンワン」と鳴きます」が表示され、Dog クラスでオーバーライドされたメソッドが適用されます。
もっと分かりやすい学習サイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいJava学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました