【Kotlin】レッスン5-06:クラスメンバとインスタンスメンバを理解しよう

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

この記事で学べる知識:クラスメンバとインスタンスメンバ

この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、関数、コレクション(レッスン1~4)クラスの定義と使用プライマリコンストラクタセカンダリコンストラクタアクセス修飾子とカプセル化クラスメンバとインスタンスメンバクラスの継承メソッドのオーバーライドクラスの拡張抽象クラスインターフェースデータクラス

<<前のページ Kotlin記事一覧 次のページ>>

Kotlinの文法「クラスメンバ」と「インスタンスメンバ」とは

ここではクラスメンバとインスタンスメンバの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。



オブジェクト指向プログラミングにおいて「クラスメンバ」と「インスタンスメンバ」は非常に重要な概念です。

これらはクラス内部で宣言される変数やメソッドの分類を示し、それぞれ異なる用途を持ちます。

本記事ではこれらの違いと具体的な使い方について詳しく解説します。

クラスメンバの概要

クラスメンバとはクラス全体に属する変数やメソッドのことです。

クラスメンバはクラスそのものに結びついており、クラスのインスタンスを作成せずに直接利用できます。

Kotlinではcompanion objectを使用してクラスメンバを定義します。

class MyClass {
    companion object {
        var classVariable: String = "I am a class variable" // クラス変数
        fun classMethod() {                                 // クラスメソッド
            println("I am a class method")
        }
    }
}

  • クラス全体で共有されるため、どのインスタンスからアクセスしても同じ値が利用される。
  • 計算処理や設定値を保持する用途でよく使用されます。
fun main() {
    println(MyClass.classVariable) // "I am a class variable"
    MyClass.classMethod()          // "I am a class method"
}

インスタンスメンバの概要

インスタンスメンバとは各インスタンスに属する変数やメソッドのことです。

インスタンスメンバはインスタンスごとに独立して存在するため、同じクラスを元に作られた複数のオブジェクト間で異なる値を持つことができます。

class MyClass {
    var instanceVariable: String = "I am an instance variable" // インスタンス変数
    fun instanceMethod() {                                     // インスタンスメソッド
        println("I am an instance method")
    }
}
  • 各インスタンス固有の値や動作を管理する際に使われる。
  • クラスを元にした複数のオブジェクトが異なるデータを扱う際に便利。
fun main() {
    val obj1 = MyClass()
    obj1.instanceVariable = "Instance 1"
    val obj2 = MyClass()
    obj2.instanceVariable = "Instance 2"
    
    println(obj1.instanceVariable) // "Instance 1"
    println(obj2.instanceVariable) // "Instance 2"
    obj1.instanceMethod() // "I am an instance method"
}

クラスメンバとインスタンスメンバの比較

特徴 クラスメンバ インスタンスメンバ
スコープ クラス全体に共有 各インスタンスに属する
アクセス方法 クラス名を通じてアクセス インスタンスを通じてアクセス
用途 共通の設定値やロジックを管理するため インスタンスごとに異なるデータや振る舞いを扱うため

例としてクラスメンバは全体のカウンター、インスタンスメンバは個別の属性値を管理する際に活用できます。

使用例

以下はクラスメンバとインスタンスメンバの両方を使った具体的なクラスの例です。

class User {
    companion object {
        var userCount: Int = 0 // クラス変数: 全体のユーザー数を保持
        fun displayUserCount() {
            println("Total users: $userCount")
        }
    }

    var name: String = "" // インスタンス変数: 各ユーザーの名前
    init {
        userCount++ // インスタンス作成時にカウントを増やす
    }

    fun displayUserInfo() {
        println("User name: $name")
    }
}

fun main() {
    val user1 = User()
    user1.name = "Alice"
    user1.displayUserInfo()

    val user2 = User()
    user2.name = "Bob"
    user2.displayUserInfo()

    User.displayUserCount() // "Total users: 2"
}
  • userCountはクラス全体で共有され、インスタンスが増えるたびにその数が増加します。
  • nameは各インスタンス固有の値を持ちます。

まとめ

クラスメンバとインスタンスメンバはクラス設計における重要な要素です。

クラス全体で共有する情報と各インスタンス固有の情報を適切に使い分けることで、コードの効率性と可読性を高めることができます。

本記事を参考に、ぜひクラスメンバとインスタンスメンバを活用してみてください!

クラスメンバとインスタンスメンバの練習問題

クラスメンバとインスタンスメンバを利用したプログラムを作成し、オブジェクト指向の基本を学びましょう。

このプログラムではユーザー情報を管理するクラスを作成します。

それぞれのユーザーごとに名前と年齢を管理し、全体のユーザー数を追跡する仕組みを実装してください。

プログラムを通じて、以下を実現します:

  • 個別のユーザー情報を出力する
  • 全体のユーザー数を出力する

この問題の要件

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

  1. クラスUserを定義すること:クラスには以下のメンバを含む。
    • クラスメンバ:
      1. companion objectを用いて全体のユーザー数を追跡するtotalUsers変数を定義する。
      2. クラスメソッドshowTotalUsersを作成し、全体のユーザー数を出力する。
    • インスタンスメンバ:
      1. name(名前)とage(年齢)を格納する変数を定義する。
      2. インスタンスメソッドdisplayUserInfoを作成し、ユーザーの名前と年齢を出力する。
  2. セカンダリコンストラクタを用いて、ユーザーの名前と年齢を初期化すること:
    • 新しいユーザーを作成するたびにtotalUsersの値を1増やすこと。
  3. メイン関数で以下を実行すること:
    • Userクラスを使って2人のユーザー(例: 太郎、25歳、花子、30歳)を作成する。
    • 各ユーザーの情報をdisplayUserInfoで出力する。
    • クラスメソッドshowTotalUsersを使用して、全体のユーザー数を出力する。

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

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

名前: 太郎, 年齢: 25
名前: 花子, 年齢: 30
現在のユーザー総数: 2

この問題を解くヒント

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

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

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

1:Userクラスの定義
  □ companion objectキーワードを使用してクラスメンバの定義
  □ □ クラス変数totalUsersを定義し、初期値を0に設定
  □ □ クラスメソッドshowTotalUsersを定義
  □ □ □ クラス変数totalUsersの値を含む文字列を出力
  □ □ companion objectブロックを終了
  □ インスタンス変数nameとageを定義
  □ セカンダリコンストラクタを定義し、nameとageを初期化
  □ □ インスタンス変数nameに引数nameを代入
  □ □ インスタンス変数ageに引数ageを代入
  □ □ クラス変数totalUsersをインクリメント
  □ セカンダリコンストラクタを終了
  □ インスタンスメソッドdisplayUserInfoを定義
  □ □ インスタンス変数nameとageを含む文字列を出力
  □ インスタンスメソッドdisplayUserInfoを終了
  □ Userクラスの定義を終了
2:main関数の定義
  □ インスタンスuser1を作成し、引数”太郎”と25を渡す
  □ インスタンスuser2を作成し、引数”花子”と30を渡す
  □ インスタンスuser1のdisplayUserInfoメソッドを呼び出し、情報を出力
  □ インスタンスuser2のdisplayUserInfoメソッドを呼び出し、情報を出力
  □ クラスメソッドshowTotalUsersを呼び出し、総ユーザー数を出力
  □ main関数の定義を終了

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

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

// ユーザー情報を管理するクラス
class User {

    // クラスメンバ(クラス全体で共通する変数)
    companion object {
        /*【穴埋め問題1】
        ここでユーザーの総数を記録する変数totalUsersを定義し、初期値を0に設定するコードを書いてください。
        */

        /*【穴埋め問題2】
        ここでユーザー総数を表示するクラスメソッドshowTotalUsersを定義し、
        現在のユーザー総数を表示するコードを書いてください。
        */
    }

    // インスタンスメンバ(個々のインスタンスが持つ変数とメソッド)
    /*【穴埋め問題3】
    ここでユーザーの名前を格納する変数nameと、年齢を格納する変数ageを定義してください。
    */

    // セカンダリコンストラクタで名前と年齢を受け取る
    /*【穴埋め問題4】
    ここでセカンダリコンストラクタを定義し、引数nameとageを受け取って
    インスタンス変数に値を代入するコードを書いてください。
    また、クラス変数totalUsersをインクリメントするコードも記述してください。
    */

    // ユーザー情報を表示するインスタンスメソッド
    /*【穴埋め問題5】
    ここでインスタンスメソッドdisplayUserInfoを定義し、
    名前と年齢を表示するコードを書いてください。
    */
}

// メイン関数
fun main() {
    // 新しいユーザーを作成
    /*【穴埋め問題6】
    ここでUserクラスのインスタンスuser1とuser2を作成し、それぞれ引数"太郎", 25と"花子", 30を渡すコードを書いてください。
    */

    // 各ユーザーの情報を表示
    /*【穴埋め問題7】
    ここでuser1とuser2のdisplayUserInfoメソッドを呼び出し、それぞれのユーザー情報を表示するコードを書いてください。
    */

    // 総ユーザー数を表示(クラスメンバを使用)
    /*【穴埋め問題8】
    ここでshowTotalUsersメソッドを呼び出し、総ユーザー数を表示するコードを書いてください。
    */
}

この問題の穴埋めコードは以上です。

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

練習問題の解答と解説

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

正解コードの例

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

// ユーザー情報を管理するクラス
class User {

    // クラスメンバ(クラス全体で共通する変数)
    companion object {
        var totalUsers: Int = 0 // ユーザーの総数を記録する
        fun showTotalUsers() { // 総数を表示するクラスメソッド
            println("現在のユーザー総数: $totalUsers")
        }
    }

    // インスタンスメンバ(個々のインスタンスが持つ変数とメソッド)
    var name: String // ユーザーの名前
    var age: Int // ユーザーの年齢

    // セカンダリコンストラクタで名前と年齢を受け取る
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
        totalUsers++ // 新しいユーザーが作成されるたびにカウントを増やす
    }

    // ユーザー情報を表示するインスタンスメソッド
    fun displayUserInfo() {
        println("名前: $name, 年齢: $age")
    }
}

// メイン関数
fun main() {
    // 新しいユーザーを作成
    val user1 = User("太郎", 25)
    val user2 = User("花子", 30)

    // 各ユーザーの情報を表示
    user1.displayUserInfo()
    user2.displayUserInfo()

    // 総ユーザー数を表示(クラスメンバを使用)
    User.showTotalUsers()
}

正解コードの解説

このコードではKotlinの「クラスメンバとインスタンスメンバ」を学ぶための基本的な仕組みを実装しています。

ユーザー情報を管理し全体のユーザー数を追跡するプログラムです。コードをブロックごとに分けて、初心者向けにわかりやすく解説します。

クラスとクラスメンバの定義

class User {
    companion object {
        var totalUsers: Int = 0
        fun showTotalUsers() {
            println("現在のユーザー総数: $totalUsers")
        }
    }
}
  1. class User:Userというクラスを定義しています。このクラスはユーザー情報を管理します。
  2. クラスメンバ(companion object:
    • クラス全体で共有される変数や関数を定義する場所です。
    • totalUsers:全体のユーザー数を記録する変数。companion objectに含まれているため、全てのインスタンスで共有されます。
    • showTotalUsers:現在のユーザー総数を出力する関数です。User.showTotalUsers()のようにクラス名を使って呼び出します。

インスタンスメンバの定義

var name: String
var age: Int
fun displayUserInfo() {
    println("名前: $name, 年齢: $age")
}
  • 各インスタンスごとに異なる値を持つ変数や関数を定義します。
  • name:各ユーザーの名前を保存する変数。
  • age:各ユーザーの年齢を保存する変数。
  • displayUserInfo:各ユーザーの名前と年齢を出力する関数です。インスタンスに対して呼び出します(例: user1.displayUserInfo())。

セカンダリコンストラクタでインスタンスを初期化

constructor(name: String, age: Int) {
    this.name = name
    this.age = age
    totalUsers++
}
  1. constructor:
    • クラスのインスタンスを作成するときに必要な情報(名前と年齢)を受け取ります。
    • this.namethis.ageで、受け取った値をインスタンスの変数に代入しています。
  2. totalUsers++:新しいユーザーが作成されるたびに、クラス全体のユーザー数を増やします。

メイン関数でクラスを活用

fun main() {
    val user1 = User("太郎", 25)
    val user2 = User("花子", 30)
    user1.displayUserInfo()
    user2.displayUserInfo()
    User.showTotalUsers()
}
  1. インスタンス作成:
    • val user1 = User("太郎", 25)のように、Userクラスのインスタンスを作成します。この時にconstructorが呼び出され、インスタンス変数が初期化されます。
  2. メソッド呼び出し:
    • 各ユーザーの情報をdisplayUserInfoで表示します。
    • クラス全体の情報(総ユーザー数)をshowTotalUsersで表示します。

まとめ

このプログラムを通じて、以下を学びました:

  1. クラスメンバとインスタンスメンバの違い:
    • クラスメンバは全てのインスタンスで共有されるのに対し、インスタンスメンバは個別のインスタンスに属します。
  2. companion objectの使い方:
    • クラス全体で共有される変数や関数を定義します。
  3. オブジェクト指向の基本概念:
    • クラスを使ったデータの管理方法と、複数のインスタンスでのデータ操作。

Kotlinのクラス構造に慣れることで、オブジェクト指向の基礎をより深く理解できます。

他のクラスメンバやインスタンスメンバを活用して、より複雑なプログラムに挑戦してみましょう!

<<前のページ Kotlin記事一覧 次のページ>>

この記事への質問・コメント

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

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






    Kotlinのテキスト&問題集トップへ戻る
    トップページへ戻る