Kotlin練習問題2-9:クラスの拡張を理解しよう

記事内に商品プロモーションを含む場合があります

Kotlinの初心者向け問題2-9:クラスの拡張を理解しよう

この問題を解くために必要な知識:
【レベル1の知識】
コメントの書き方、変数と定数、基本データ型、算術演算と論理演算、入力と出力、import文、配列、分岐処理(if、if~else、when)、繰り返し処理(for、while、do~while)、Null安全、スマートキャスト

【レベル2の知識】
関数の定義と呼び出し、関数の戻り値関数のオーバーロードラベルとジャンプ例外処理、クラスの定義と使用、インスタンス、コンストラクタ、プロパティ、クラスの継承、クラスの拡張

<<前の問題 問題集Top 次の問題>>

Kotlinの文法「クラスの拡張」とは

ここではクラスの拡張の意味や使い方を復習します。必要ない方はここをクリックして練習問題へ飛びましょう。



Kotlinのクラス拡張機能を使うと、既存のクラスを変更せずに新しいメソッドやプロパティを追加することができます。

これは、オブジェクト指向プログラミングの強力な手法であり、コードの再利用性や保守性を大幅に向上させることができます。

今回は、その基本的な使い方を解説します。

クラスの拡張とは?

クラスの拡張とは、既存のクラスの振る舞いを追加・変更するための方法です。

Kotlinでは、クラス本体を修正せずに、拡張関数やプロパティを使って新しい機能をクラスに追加できます。

この機能により、ライブラリや外部コードを直接変更することなく、自分のプロジェクトに必要な機能を簡単に追加することが可能です。

たとえば、Stringクラスに新しいメソッドを追加したい場合、以下のようにクラスを拡張できます。

クラス拡張の使用例

次に、Stringクラスを拡張して、文字列が回文(前から読んでも後ろから読んでも同じ)かどうかを判定する新しいメソッドを追加する例を見ていきましょう。

// Stringクラスの拡張関数
fun String.isPalindrome(): Boolean {
    return this == this.reversed()
}

fun main() {
    val word = "racecar"
    println(word.isPalindrome()) // true
}

このコードでは、Kotlinの標準ライブラリに含まれているStringクラスに対してisPalindrome()という拡張関数を追加しています。

isPalindrome()は、その文字列が回文かどうかを判断し、結果をBoolean型で返します。

例えば、racecarという文字列は前から読んでも後ろから読んでも同じなので、このメソッドはtrueを返します。

Kotlinのクラス拡張の注意点

Kotlinのクラス拡張は便利ですが、いくつか注意すべき点があります。

  1. 既存のメソッドをオーバーライドできない:拡張関数では、既存のクラスのメソッドを上書きすることはできません。そのため、同じ名前のメソッドを定義しても、クラス本来のメソッドが優先されます。
  2. 静的解決:拡張関数は、クラスのインスタンスメソッドとして追加されるのではなく、あくまで静的に解決されます。これは、クラスの内部に直接追加されるわけではないということです。

まとめ

Kotlinのクラス拡張は、外部コードを変更せずに機能を追加するための非常に柔軟な方法です。

これにより、標準ライブラリや外部ライブラリのクラスに対しても、必要な機能を簡単に追加することができます。

ただし、拡張機能にはオーバーライドができないなどの制約があるため、その点を理解した上で活用することが大切です。




Kotlin練習問題2-9:車の拡張クラスを作成して車の詳細情報を表示する

Kotlinで「クラスの継承と拡張」を理解するために、車とトラックを表すプログラムを作成しましょう。

このプログラムでは、基本となるVehicleクラスを定義し、そこからCarクラスとTruckクラスを継承して作成します。

それぞれのクラスに固有のプロパティやメソッドを追加することで、クラスの拡張について学びます。

この問題の要件

以下の要件に従ってプログラムを作成してください。

  • Vehicleという名前のクラスを作成し、name(名前)とspeed(速度)という2つのプロパティを持たせること。このプロパティはコンストラクタを使用して初期化します。
  • Vehicleクラスに、車の名前と速度を表示するためのdisplayInfo関数を定義すること。この関数では、namespeedプロパティの値を使用して、「車の名前: [name], 速度: [speed] km/h」とコンソールに出力します。
  • Vehicleクラスを継承したCarクラスを作成し、fuelType(燃料の種類)という新しいプロパティを追加すること。このプロパティもコンストラクタを使用して初期化します。
  • Carクラスに、車のホーン音を表示するhonk関数と、燃料の種類を表示するdisplayFuelType関数を定義すること。
  • Vehicleクラスを継承したTruckクラスを作成し、capacity(積載量)という新しいプロパティを追加すること。このプロパティもコンストラクタを使用して初期化します。
  • Truckクラスに、トラックのホーン音を表示するhonk関数と、積載量を表示するdisplayCapacity関数を定義すること。
  • main関数を作成し、CarクラスとTruckクラスのインスタンスを作成して、それぞれのプロパティとメソッドを使って情報をコンソールに出力すること。

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

----- ↓出力される結果の例↓ -----

車の名前: フェラーリ, 速度: 300 km/h
フェラーリ はビーッと鳴らしています。
フェラーリ の燃料の種類: ガソリン
車の名前: ボルボ, 速度: 100 km/h
ボルボ はブォーと鳴らしています。
ボルボ の積載量: 15 トン

----- ↑出力される結果の例↑ -----

この問題を解くヒント

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

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

正解のコードは上から順に以下のような構成となっています。

1.Vehicleクラスの定義
 1-1. プロパティnameとspeedの宣言およびコンストラクタによる初期化
 1-2. displayInfo関数の定義(車の名前と速度を表示するメソッド)

2.Carクラスの定義
 2-1. Vehicleクラスの継承
 2-2. プロパティfuelTypeの宣言およびコンストラクタによる初期化
 2-3. honk関数の定義(車のホーン音を表示するメソッド)
 2-4. displayFuelType関数の定義(燃料の種類を表示するメソッド)

3.Truckクラスの定義
 3-1. Vehicleクラスの継承
 3-2. プロパティcapacityの宣言およびコンストラクタによる初期化
 3-3. honk関数の定義(トラックのホーン音を表示するメソッド)
 3-4. displayCapacity関数の定義(積載量を表示するメソッド)

4.main関数の定義
 4-1. Carクラスのインスタンス化
 4-2. Truckクラスのインスタンス化
 4-3. displayInfo関数を使用して車の名前と速度を表示
 4-4. honk関数を使用して車のホーン音を表示
 4-5. displayFuelType関数を使用して燃料の種類を表示
 4-6. displayInfo関数を使用してトラックの名前と速度を表示
 4-7. honk関数を使用してトラックのホーン音を表示
 4-8. displayCapacity関数を使用して積載量を表示

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

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

// Vehicleクラスを定義
open class Vehicle(val name: String, val speed: Int) {
    // 名前と速度を表示する関数
    fun displayInfo() {
        /* 【穴埋め問題1】
        ここにnameとspeedプロパティを使用して、車の名前と速度を表示するコードを書いてください。
        例: println("車の名前: $name, 速度: $speed km/h")
        */
    }
}

// CarクラスをVehicleクラスから継承
class Car(name: String, speed: Int, val fuelType: String) : Vehicle(name, speed) {
    // 車のホーン音を表示する関数
    fun honk() {
        /* 【穴埋め問題2】
        ここにnameプロパティを使用して、車のホーン音を表示するコードを書いてください。
        例: println("$name はビーッと鳴らしています。")
        */
    }
    
    // 燃料の種類を表示する関数
    fun displayFuelType() {
        /* 【穴埋め問題3】
        ここにnameとfuelTypeプロパティを使用して、燃料の種類を表示するコードを書いてください。
        例: println("$name の燃料の種類: $fuelType")
        */
    }
}

// TruckクラスをVehicleクラスから継承
class Truck(name: String, speed: Int, val capacity: Int) : Vehicle(name, speed) {
    // トラックのホーン音を表示する関数
    fun honk() {
        /* 【穴埋め問題4】
        ここにnameプロパティを使用して、トラックのホーン音を表示するコードを書いてください。
        例: println("$name はブォーと鳴らしています。")
        */
    }

    // 積載量を表示する関数
    fun displayCapacity() {
        /* 【穴埋め問題5】
        ここにnameとcapacityプロパティを使用して、積載量を表示するコードを書いてください。
        例: println("$name の積載量: $capacity トン")
        */
    }
}

fun main() {
    // Carクラスのインスタンスを作成
    /* 【穴埋め問題6】
    ここにCarクラスのインスタンスを作成するコードを書いてください。
    例: val car = Car("フェラーリ", 300, "ガソリン")
    */
    
    // Truckクラスのインスタンスを作成
    /* 【穴埋め問題7】
    ここにTruckクラスのインスタンスを作成するコードを書いてください。
    例: val truck = Truck("ボルボ", 100, 15)
    */
    
    // 車の名前と速度を表示
    /* 【穴埋め問題8】
    ここにcarインスタンスのdisplayInfo関数を呼び出すコードを書いてください。
    例: car.displayInfo()
    */

    // 車のホーン音を表示
    /* 【穴埋め問題9】
    ここにcarインスタンスのhonk関数を呼び出すコードを書いてください。
    例: car.honk()
    */
    
    // 燃料の種類を表示
    /* 【穴埋め問題10】
    ここにcarインスタンスのdisplayFuelType関数を呼び出すコードを書いてください。
    例: car.displayFuelType()
    */
    
    // トラックの名前と速度を表示
    /* 【穴埋め問題11】
    ここにtruckインスタンスのdisplayInfo関数を呼び出すコードを書いてください。
    例: truck.displayInfo()
    */

    // トラックのホーン音を表示
    /* 【穴埋め問題12】
    ここにtruckインスタンスのhonk関数を呼び出すコードを書いてください。
    例: truck.honk()
    */
    
    // 積載量を表示
    /* 【穴埋め問題13】
    ここにtruckインスタンスのdisplayCapacity関数を呼び出すコードを書いてください。
    例: truck.displayCapacity()
    */
}

 

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

解答例

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

********************

// Vehicleクラスを定義
open class Vehicle(val name: String, val speed: Int) {
    // 名前と速度を表示する関数
    fun displayInfo() {
        println("車の名前: $name, 速度: $speed km/h")
    }
}

// CarクラスをVehicleクラスから継承
// クラスの拡張:Vehicleクラスに新たにfuelTypeプロパティを追加し、Carクラス固有の機能を持たせています
class Car(name: String, speed: Int, val fuelType: String) : Vehicle(name, speed) {
    // 車のホーン音を表示する関数
    fun honk() {
        println("$name はビーッと鳴らしています。")
    }
    
    // 燃料の種類を表示する関数
    // クラスの拡張:Carクラス固有のメソッド
    fun displayFuelType() {
        println("$name の燃料の種類: $fuelType")
    }
}

// TruckクラスをVehicleクラスから継承
// クラスの拡張:Vehicleクラスに新たにcapacityプロパティを追加し、Truckクラス固有の機能を持たせています
class Truck(name: String, speed: Int, val capacity: Int) : Vehicle(name, speed) {
    // トラックのホーン音を表示する関数
    fun honk() {
        println("$name はブォーと鳴らしています。")
    }

    // 積載量を表示する関数
    // クラスの拡張:Truckクラス固有のメソッド
    fun displayCapacity() {
        println("$name の積載量: $capacity トン")
    }
}

fun main() {
    // Carクラスのインスタンスを作成
    val car = Car("フェラーリ", 300, "ガソリン")
    // Truckクラスのインスタンスを作成
    val truck = Truck("ボルボ", 100, 15)

    // 車の名前と速度を表示
    car.displayInfo()
    // 車のホーン音を表示
    car.honk()
    // 燃料の種類を表示
    car.displayFuelType()

    // トラックの名前と速度を表示
    truck.displayInfo()
    // トラックのホーン音を表示
    truck.honk()
    // 積載量を表示
    truck.displayCapacity()
}

********************

コードの解説

このコードでは、Kotlinにおける「クラスの継承」と「クラスの拡張」について学びます。以下、コードの各部分を初心者向けに説明します。

Vehicleクラスの定義

open class Vehicle(val name: String, val speed: Int) {
    fun displayInfo() {
        println("車の名前: $name, 速度: $speed km/h")
    }
}
  • open class Vehicle(val name: String, val speed: Int): Vehicleクラスは基本的な車両を表すクラスです。namespeedという2つのプロパティを持ちます。openキーワードは、このクラスが他のクラスから継承されることを許可します。
  • fun displayInfo(): この関数は、車両の名前と速度を表示します。println関数を使って、namespeedのプロパティを出力します。

Carクラスの定義

class Car(name: String, speed: Int, val fuelType: String) : Vehicle(name, speed) {
    fun honk() {
        println("$name はビーッと鳴らしています。")
    }
    
    fun displayFuelType() {
        println("$name の燃料の種類: $fuelType")
    }
}
  • class Car(name: String, speed: Int, val fuelType: String) : Vehicle(name, speed): CarクラスはVehicleクラスを継承しています。これにより、Vehicleクラスの機能をそのまま使用しつつ、fuelTypeプロパティを追加して車の燃料タイプを管理します。
  • fun honk(): この関数は車のホーン音を表示します。nameプロパティを使用して、特定の車がホーンを鳴らしていることを表現します。
  • fun displayFuelType(): この関数は車の燃料の種類を表示します。namefuelTypeプロパティを使用して、車の詳細を出力します。

Truckクラスの定義

class Truck(name: String, speed: Int, val capacity: Int) : Vehicle(name, speed) {
    fun honk() {
        println("$name はブォーと鳴らしています。")
    }

    fun displayCapacity() {
        println("$name の積載量: $capacity トン")
    }
}
  • class Truck(name: String, speed: Int, val capacity: Int) : Vehicle(name, speed): TruckクラスもVehicleクラスを継承していますが、積載量を管理するcapacityプロパティが追加されています。
  • fun honk(): トラックのホーン音を表示する関数です。nameプロパティを使用して、特定のトラックがホーンを鳴らしていることを表現します。
  • fun displayCapacity(): この関数はトラックの積載量を表示します。namecapacityプロパティを使用して、トラックの詳細を出力します。

main関数の定義

fun main() {
    val car = Car("フェラーリ", 300, "ガソリン")
    val truck = Truck("ボルボ", 100, 15)
    
    car.displayInfo()
    car.honk()
    car.displayFuelType()
    
    truck.displayInfo()
    truck.honk()
    truck.displayCapacity()
}
  • val car = Car("フェラーリ", 300, "ガソリン"): Carクラスのインスタンスを作成し、フェラーリという名前、300km/hの速度、ガソリンの燃料タイプを設定します。
  • val truck = Truck("ボルボ", 100, 15): Truckクラスのインスタンスを作成し、ボルボという名前、100km/hの速度、15トンの積載量を設定します。
  • car.displayInfo()car.honk()car.displayFuelType(): Carクラスのインスタンスcarの情報を表示し、ホーン音と燃料の種類を出力します。
  • truck.displayInfo()truck.honk()truck.displayCapacity(): Truckクラスのインスタンスtruckの情報を表示し、ホーン音と積載量を出力します。
<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Kotlin練習問題集へ戻る
    トップページへ戻る