【Kotlin】レッスン5-4:ふたつのコンストラクタの違いを理解しよう

ながみえ

一つ前のページではセカンダリコンストラクタについて学習しました。

今回は ふたつのコンストラクタの違いについて見ていきましょう。

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:石取りゲームを作ろう

<<前のページ

学習記事一覧

次のページ>>

2種類のコンストラクタを復習しよう|構文と使い分けを解説

コンストラクタは、クラスのインスタンスを作成する際に初期化を行う特別な仕組みです。

コンストラクタには「プライマリコンストラクタ」と「セカンダリコンストラクタ」という2種類があり、それぞれ異なる特徴と用途を持ちます。

本記事では、それぞれの構文や使い方を簡単に振り返り、両者の違いの比較を行います。

プライマリコンストラクタの基本構文と利点

プライマリコンストラクタは、クラス名に直接付随して定義されるシンプルなコンストラクタです。

次の例を見てみましょう。

class User(val name: String, val age: Int) {	// プライマリコンストラクタを持つUserクラスの定義
    init {										// initブロックの定義
        println("User created: $name, $age")	// プライマリコンストラクタの処理内容
    }
}

上記の例ではUserクラスにプライマリコンストラクタが定義されており、インスタンス生成時に自動でメッセージを出力する処理を行っています。

この構文ではコンストラクタの引数nameageを使ってクラスのプロパティを直接初期化しています。

  • シンプルで簡潔に記述可能
  • 初期化処理をinitブロックで追加可能

セカンダリコンストラクタの基本構文と利点

セカンダリコンストラクタは、constructorキーワードを使ってクラス本体内に定義されるコンストラクタです。

複雑な初期化処理が必要な場合に役立ちます。

class User {								// プライマリコンストラクタを持たないUserクラスの定義
    var name: String
    var age: Int

    constructor(name: String, age: Int) {	// セカンダリコンストラクタの定義
        this.name = name					// セカンダリコンストラクタの処理内容
        this.age = age						// "この"コンストラクタのageに引数のageを代入
    }
}

このコードではセカンダリコンストラクタにより、インスタンス毎に変数の値を変えられる処理となっています。

  • より柔軟な初期化処理が可能
  • 複数の初期化方法を用意し、オーバーロードさせることも可能

2つのコンストラクタの違いと同時に使うコード例

2つのコンストラクタの違いをまとめると以下のようになります。

比較内容プライマリコンストラクタセカンダリコンストラクタ
構文のシンプルさ簡潔少し冗長
柔軟性限定的高い
主な用途プロパティの簡単な初期化複雑な初期化処理
  • プライマリコンストラクタ:単純なプロパティの初期化が必要な場合に最適。
  • セカンダリコンストラクタ:初期化ロジックが複雑な場合や、異なる方法でインスタンスを生成したい場合に使用。

また、プライマリとセカンダリを同時に使用する場合は、「セカンダリを通してプライマリを実行」という処理が行われます。

つまり実行される初期化は1回だけです。

その場合、セカンダリの定義時に「: this(…)」と書いて、プライマリに値を渡します。

class User(val name: String, var age: Int) { // プライマリコンストラクタでnameとageを初期化

    init { // プライマリの初期化ブロック
        println("User created: name=$name, age=$age")
    }
    
    // セカンダリコンストラクタ1(nameのみ指定、ageはデフォルトで0)
    constructor(name: String) : this(name, 0)
    // セカンダリコンストラクタ2(引数なし、nameは"Guest"、ageは0)
    constructor() : this("Guest", 0)
}

fun main() {
    val user1 = User("Alice", 25)   // プライマリコンストラクタ
    val user2 = User("Bob")         // セカンダリコンストラクタ1
    val user3 = User()              // セカンダリコンストラクタ2
}

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

User created: name=Alice, age=25
User created: name=Bob, age=0
User created: name=Guest, age=0

セカンダリを呼び出していても、プライマリの中のメソッドが実行されている点に着目しましょう。

プライマリを定義していない場合は、「何もないデフォルトのプライマリを通している」と表現することもできます。

まとめ|コンストラクタを正しく使い分けよう

コンストラクタは、Kotlinでクラスを使用する上で欠かせない機能です。

プライマリコンストラクタとセカンダリコンストラクタの違いを理解することで、シンプルで効果的なコードを書くことができます。

次回は、アクセス修飾子を活用したカプセル化について学んでいきましょう。

練習問題|プライマリ・セカンダリコンストラクタで柔軟な初期化を体験しよう

「プライマリコンストラクタ」と「セカンダリコンストラクタ」を使用して、インスタンス生成とプロパティの初期化を学ぶプログラムを作成しましょう。

このプログラムではPersonクラスを用いて名前と年齢を設定する方法を体験し、さらに趣味を追加するセカンダリコンストラクタの使い方を確認します。

この問題の要件

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

  1. Personクラスを定義すること。
    • プライマリコンストラクタで名前 (name) と年齢 (age) を受け取り、それをプロパティとして保持すること。
    • 初期化ブロック (init) で、インスタンス生成時に名前と年齢を表示すること。
  2. Personクラスにセカンダリコンストラクタを追加すること。
    • 名前と年齢に加え、趣味 (hobby) を受け取るコンストラクタを作成すること。
    • セカンダリコンストラクタ内で趣味を設定し、それを表示すること。
  3. showInfo関数を定義し、名前、年齢、趣味を出力すること。
  4. main関数内で以下を行うこと。
    • プライマリコンストラクタを使ってインスタンスを生成し、showInfoを呼び出して情報を表示すること。
    • セカンダリコンストラクタを使ってインスタンスを生成し、showInfoを呼び出して情報を表示すること。

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

初期化: 太郎 さんの年齢は 25 歳です。
名前: 太郎, 年齢: 25, 趣味: 不明
初期化: 花子 さんの年齢は 30 歳です。
趣味が登録されました: 趣味は 読書 です。
名前: 花子, 年齢: 30, 趣味: 読書

この問題を解くヒント

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

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

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

1:Personクラスの定義
  □ nameとageを引数とするプライマリコンストラクタを定義
  □ 変数hobbyを初期値”不明”で定義
  □ initブロックにて初期化処理を実行
  □ □ nameとageを出力する
  □ セカンダリコンストラクタを定義
  □ □ プライマリコンストラクタを呼び出し、hobbyを設定
  □ □ hobbyを出力する
  □ showInfo関数を定義
  □ □ name, age, hobbyを出力する
2:main関数の定義
  □ Personクラスのインスタンスperson1をプライマリコンストラクタで生成
  □ person1の情報を表示
  □ Personクラスのインスタンスperson2をセカンダリコンストラクタで生成
  □ person2の情報を表示

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

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

// Person クラスの定義
// このクラスではプライマリコンストラクタとセカンダリコンストラクタを使用します。
class Person(/*【穴埋め問題1】ここにプライマリコンストラクタの引数を定義してください*/) { 
    var hobby: String = "不明" // 趣味のデフォルト値

    // 初期化ブロック。インスタンス生成時に実行されます。
    init {
        println("初期化: $name さんの年齢は $age 歳です。")
    }

    // セカンダリコンストラクタ
    /*【穴埋め問題2】ここにセカンダリコンストラクタを定義し、hobbyを設定するコードを書いてください*/

    // Personの情報を表示するメソッド
    fun showInfo() {
        println("名前: $name, 年齢: $age, 趣味: $hobby")
    }
}

// メイン関数
fun main() {
    // プライマリコンストラクタを使ってインスタンスを作成
    /*【穴埋め問題3】ここにプライマリコンストラクタを使ってインスタンスを作成するコードを書いてください*/
    person1.showInfo() // 情報を表示

    // セカンダリコンストラクタを使ってインスタンスを作成
    /*【穴埋め問題4】ここにセカンダリコンストラクタを使ってインスタンスを作成するコードを書いてください*/
    person2.showInfo() // 情報を表示
}

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

この問題の解答と解説

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

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

Q
正解コード
// Person クラスの定義
// このクラスではプライマリコンストラクタとセカンダリコンストラクタを使用します。
class Person(val name: String, val age: Int) { // プライマリコンストラクタ
    var hobby: String = "不明" // 趣味のデフォルト値

    // 初期化ブロック。インスタンス生成時に実行されます。
    init {
        println("初期化: $name さんの年齢は $age 歳です。")
    }

    // セカンダリコンストラクタ
    constructor(name: String, age: Int, hobby: String) : this(name, age) {
        this.hobby = hobby
        println("趣味が登録されました: 趣味は $hobby です。")
    }

    // Personの情報を表示するメソッド
    fun showInfo() {
        println("名前: $name, 年齢: $age, 趣味: $hobby")
    }
}

// メイン関数
fun main() {
    // プライマリコンストラクタを使ってインスタンスを作成
    val person1 = Person("太郎", 25)
    person1.showInfo() // 情報を表示

    // セカンダリコンストラクタを使ってインスタンスを作成
    val person2 = Person("花子", 30, "読書")
    person2.showInfo() // 情報を表示
}
Q
正解コードの解説

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

クラスの定義

class Person(val name: String, val age: Int) {
    var hobby: String = "不明"
    init {
        println("初期化: $name さんの年齢は $age 歳です。")
    }
    constructor(name: String, age: Int, hobby: String) : this(name, age) {
        this.hobby = hobby
        println("趣味が登録されました: 趣味は $hobby です。")
    }
    fun showInfo() {
        println("名前: $name, 年齢: $age, 趣味: $hobby")
    }
}
  • class Person: Personクラスを定義しています。クラスはオブジェクトのテンプレートであり、属性や動作を持ちます。
  • プライマリコンストラクタ: クラス名の隣に記述されているコンストラクタです。この例では、nameageという2つのプロパティを初期化しています。
  • initブロック: インスタンス生成時に実行されるコードを記述する場所です。このコードでは、生成されたインスタンスの名前と年齢を表示しています。
  • セカンダリコンストラクタ: constructorキーワードを使って追加のコンストラクタを定義しています。このコンストラクタでは趣味 (hobby) を受け取り、thisを使ってプライマリコンストラクタを呼び出しています。

メイン関数

fun main() {
    val person1 = Person("太郎", 25)
    person1.showInfo()
    val person2 = Person("花子", 30, "読書")
    person2.showInfo()
}
  1. fun main(): Kotlinプログラムのエントリーポイントです。
  2. val person1 = Person("太郎", 25):
    • プライマリコンストラクタを使用してPersonクラスのインスタンスを作成します。
    • name"太郎", age25に設定されます。
  3. person1.showInfo():
    • メソッドshowInfoを呼び出し、インスタンスの詳細を表示します。
  4. val person2 = Person("花子", 30, "読書"):
    • セカンダリコンストラクタを使用してインスタンスを作成します。
    • hobbyとして"読書"も設定します。
Q
サイト改善アンケート & ご指摘/ご質問

本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
そのため、みなさまの「プログラミングを学習する理由」などを アンケート 形式でお伺いしています。

また記事の内容に関する ご指摘ご質問 もお待ちしています。

1.このサイトをどのように活用していますか?また、今後どのように活用したいですか?
5.気になっているサービス・商品があれば教えてください。
※ 特定の記事に関する内容の場合は、記事番号(レッスン〇-〇)をご記入願います。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました