【Kotlin】レッスン5-08:メソッドのオーバーライドの仕組みと使い方を基礎から解説

tggaa478@yahoo.co.jp

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

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

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編
Lesson4:コレクション編
Lesson5:オブジェクト指向編

 ・Lesson5-1:クラスの基本を理解しよう
 ・Lesson5-2:プライマリコンストラクタを理解しよう
 ・Lesson5-3:セカンダリコンストラクタを理解しよう
 ・Lesson5-4:ふたつのコンストラクタを使いこなそう
 ・Lesson5-5:アクセス修飾子とカプセル化を理解しよう
 ・Lesson5-6:クラスメンバとインスタンスメンバを理解しよう
 ・Lesson5-7:クラスの継承を理解しよう
 ・Lesson5-8:メソッドのオーバーライドを理解しよう ◁今回はココ
 ・Lesson5-9:クラスを拡張しよう
 ・Lesson5-10:抽象クラスを理解しよう
 ・Lesson5-11:インターフェースを理解しよう
 ・Lesson5-12:データクラスを理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:マルバツゲームを作ろう
 ・確認問題5-☆3:石取りゲームを作ろう

<<前のページ

学習記事一覧

次のページ>>

メソッドのオーバーライド|定義・構文・注意点を解説

Kotlinにおいて「メソッドのオーバーライド」は、親クラスで定義されたメソッドを子クラスで再定義し、新たな挙動を与える機能です。

オブジェクト指向の特性を活かし、柔軟で再利用可能なコード設計に役立ちます。

オーバーライドとは何か?親クラスと子クラスの関係を理解しよう

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

これにより子クラスで特定の処理を上書きし、クラスの振る舞いを変更できます。

オーバーライドを使用するには、親クラスの関数がopen修飾子を持ち、子クラスではoverrideキーワードを使用する必要があります。

Kotlinでのオーバーライド構文|openとoverrideの使い方

Kotlinで関数をオーバーライドする基本構文は以下の通りです。

open class Parent {     // 親クラスとして使用されるParentクラスの定義
    open fun greet() {  // オーバーライドされることを想定したgreetメソッド
        println("Hello from Parent")
    }
}

class Child : Parent() {   // Parentクラスを継承したChildクラスの定義
    override fun greet() { // Parentクラスのgreetメソッドをオーバーライド
        println("Hello from Child")
    }
}
  • 親クラスParentのメソッドgreetopenキーワードを使用して再定義可能にしています。
  • 子クラスChildではoverrideキーワードを使用して新しい実装を提供しています。

オーバーライドの具体例|動物クラスを使った継承の実装

メソッドのオーバーライドを活用した具体的なコード例を示します。

open class Animal {        // 親クラスとして使用するAnimalクラスの定義
    open fun makeSound() { // オーバーライドされることを想定したmakeSoundメソッドを定義
        println("Some generic animal sound")
    }
}

class Dog : Animal() {         // Animalクラスを継承したDogクラスを定義
    override fun makeSound() { // AnimalクラスのmakeSoundメソッドをオーバーライド
        println("Bark!")
    }
}

class Cat : Animal() {         // Animalクラスを継承したCatクラスを定義
    override fun makeSound() { // AnimalクラスのmakeSoundメソッドをオーバーライド
        println("Meow!")
    }
}

fun main() {
    val animals: List<Animal> = listOf(Dog(), Cat(), Animal())
    for (animal in animals) {
        animal.makeSound() // 各クラスに応じたサウンドが出力される
    }
}
  • 親クラスAnimalは汎用的な動物の行動を定義します。
  • 子クラスDogCatはそれぞれ特定の動物の挙動をmakeSound関数で再定義しています。
  • forループではリスト内の各インスタンスに応じて異なるメッセージが出力されます。

このコードを実行すると以下のように出力されます。

Bark!
Meow!
Some generic animal sound

オーバーライド時の注意点|アクセス修飾子とエラー回避策

  1. openキーワード: 親クラスのメソッドはデフォルトでオーバーライドが禁止されています。オーバーライド可能にするにはopen修飾子を付ける必要があります。
  2. overrideキーワード: 子クラスでメソッドをオーバーライドする際は、必ずoverrideキーワードを使用します。これにより誤った再定義を防ぎます。
  3. アクセス修飾子: 親クラスと子クラス間で関数の可視性に互換性が必要です。例えば、protected関数をpublicに変更することは可能ですが、privateにすることはできません。

メソッドのオーバーライドを使いこなすためのまとめ

Kotlinのメソッドのオーバーライドは、コードの柔軟性と再利用性を高める強力な機能です。

オーバーライドを正しく活用することで、親クラスの汎用性と子クラスの特化性を両立させ、オブジェクト指向プログラミングの真価を発揮できます。

練習問題|メソッドのオーバーライドを使った多態性の理解を深めよう

乗り物の動きを表現するプログラムを作成し、Kotlinの「メソッドのオーバーライド」を学びましょう。

基本となる「乗り物」のクラスを作成し、それを継承して「車」「船」「飛行機」の動きをそれぞれ異なる方法で実装します。

最後にこれらの乗り物の動きを表示するプログラムを作成してください。

この問題の要件

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

  1. クラス Vehicle を作成すること。
    • move() という関数を定義し、「乗り物が移動します」と出力すること。
  2. クラス Car を作成し、Vehicle クラスを継承すること。
    • move() 関数をオーバーライドし、「車が道路を走ります」と出力すること。
  3. クラス Boat を作成し、Vehicle クラスを継承すること。
    • move() 関数をオーバーライドし、「船が水上を進みます」と出力すること。
  4. クラス Airplane を作成し、Vehicle クラスを継承すること。
    • move() 関数をオーバーライドし、「飛行機が空を飛びます」と出力すること。
  5. main関数 を作成すること。
    • Vehicle 型のリストを作成し、CarBoatAirplane のインスタンスをリストに追加すること。
    • すべてのインスタンスで move() 関数を呼び出し、動作を表示すること。

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

車が道路を走ります
船が水上を進みます
飛行機が空を飛びます

この問題を解くヒント

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

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


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

1:Vehicleクラスの定義
  □ moveメソッドの定義(open修飾子付き)
2:Carクラスの定義(Vehicleクラスを継承)
  □ moveメソッドをオーバーライド
3:Boatクラスの定義(Vehicleクラスを継承)
  □ moveメソッドをオーバーライド
4:Airplaneクラスの定義(Vehicleクラスを継承)
  □ moveメソッドをオーバーライド
5:main関数の定義
  □ Vehicle型のリストを作成し、Car、Boat、Airplaneのインスタンスを格納
  □ forループによりリストの各要素について処理
  □ □ moveメソッドを呼び出す

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

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

// 基本的な乗り物のクラス
open class Vehicle {
    /*【穴埋め問題1】
    ここにmoveメソッドを定義し、「乗り物が移動します」と出力するコードを書いてください。
    */
}

// 車クラス(Vehicleクラスを継承)
class Car : Vehicle() {
    /*【穴埋め問題2】
    ここにmoveメソッドをオーバーライドし、「車が道路を走ります」と出力するコードを書いてください。
    */
}

// 船クラス(Vehicleクラスを継承)
class Boat : Vehicle() {
    /*【穴埋め問題3】
    ここにmoveメソッドをオーバーライドし、「船が水上を進みます」と出力するコードを書いてください。
    */
}

// 飛行機クラス(Vehicleクラスを継承)
class Airplane : Vehicle() {
    /*【穴埋め問題4】
    ここにmoveメソッドをオーバーライドし、「飛行機が空を飛びます」と出力するコードを書いてください。
    */
}

fun main() {
    // Vehicle型のリストを作成
    val vehicles: List<Vehicle> = listOf(Car(), Boat(), Airplane())

    // 各乗り物に応じた動作を表示
    for (vehicle in vehicles) {
        // 【穴埋め問題5】ここでvehicleオブジェクトのmoveメソッドを呼び出してください。
    }
}

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

練習問題の解答と解説

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

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

Q
正解コード
// 基本的な乗り物のクラス
open class Vehicle {
    // 乗り物の走行方法を表す関数
    open fun move() {
        println("乗り物が移動します")
    }
}

// 車クラス(Vehicleクラスを継承)
class Car : Vehicle() {
    // moveメソッドをオーバーライドして車特有の動作を実装
    override fun move() {
        println("車が道路を走ります")
    }
}

// 船クラス(Vehicleクラスを継承)
class Boat : Vehicle() {
    // moveメソッドをオーバーライドして船特有の動作を実装
    override fun move() {
        println("船が水上を進みます")
    }
}

// 飛行機クラス(Vehicleクラスを継承)
class Airplane : Vehicle() {
    // moveメソッドをオーバーライドして飛行機特有の動作を実装
    override fun move() {
        println("飛行機が空を飛びます")
    }
}

fun main() {
    // Vehicle型のリストを作成
    val vehicles: List<Vehicle> = listOf(Car(), Boat(), Airplane())

    // 各乗り物に応じた動作を表示
    for (vehicle in vehicles) {
        // オーバーライドされたメソッドが呼び出されることを確認
        vehicle.move()
    }
}
Q
正解コードの解説

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

クラス Vehicle の定義

open class Vehicle {
    open fun move() {
        println("乗り物が移動します")
    }
}
  • open 修飾子: Kotlinではクラスやメソッドを継承可能にするには open を付ける必要があります。Vehicle クラスは他のクラスに継承されるためopen を指定しています。
  • move メソッド: 基本的な乗り物の動きを表現しています。このメソッドはオーバーライドされるためopen を付けています。

Car, Boat, Airplane クラスの定義と move メソッドのオーバーライド

class Car : Vehicle() {
    override fun move() {
        println("車が道路を走ります")
    }
}

class Boat : Vehicle() {
    override fun move() {
        println("船が水上を進みます")
    }
}

class Airplane : Vehicle() {
    override fun move() {
        println("飛行機が空を飛びます")
    }
}
  • class Car : Vehicle(): クラス CarVehicle を継承しています。: を使用して親クラスを指定します。
  • override 修飾子: 親クラスのメソッドを再定義する際に使います。このコードではそれぞれの乗り物に特有の動きを表現するため、move メソッドをオーバーライドしています。

main 関数でリストを使用して動作を表示

fun main() {
    val vehicles: List<Vehicle> = listOf(Car(), Boat(), Airplane())

    for (vehicle in vehicles) {
        vehicle.move()
    }
}
  • List: Kotlinのコレクション型の一つで複数の要素を保持できます。この場合、Vehicle 型のリストを作成しています。
  • listOf(Car(), Boat(), Airplane()): CarBoatAirplane のインスタンスをリストに追加します。
  • for: リストの各要素に対して繰り返し処理を行います。vehicle.move() によって、それぞれのオーバーライドされた move メソッドが呼び出されます。

まとめ

このプログラムではKotlinの「継承」と「メソッドのオーバーライド」の基礎を学びました。

実際にコードを動かしながら学ぶことで、理解が深まるでしょう!

次のステップとして自分で新しい乗り物を追加して、さらに異なる動きをプログラムに実装してみてください。

これによってオーバーライドの応用力が高まります。

もっと分かりやすいサイトにするために

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

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

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました