Android / Programming

ザクっと理解するKotlin Data classes(データクラス)

データクラスについてKotlinの公式文章をもとにまとめました。

データクラスとは

Kotlinでは、データを保持するためだけのクラスをデータクラスと呼び、基本的な関数を自動で提供する機能があります。
データクラスの作成ではdataキーワードをclassキーワードの前につけます。

data class DataClass01(var name: String, var age: Int)

コンパイラは、プライマリコンストラクタで宣言されたすべてのプロパティから、以下のメンバーを自動的に作成します。

・equals()
・hashCode()
・toString() 表示例「DataClass01(name=TEST, age=10)」
・componentN() プロパティの宣言順に対応
・copy()

作成されたコードの一貫性と存在意義を保証するため、データクラスは下記を満たす必要があります。

・プライマリコンストラクタは少なくとも1つのパラメータを持つこと
・全てのプライマリコンストラクタのパラメータはvalまたはvarで宣言されること
・データクラスはabstract(抽象的)、オープン(open)、シールド(sealed)、インナー(inner)にはしないこと

さらに、データクラスのメンバー生成には、次のルールが継承に関して適用されます。

・データクラスのボディで実装がある、もしくはスーパークラスでfinalな実装があるequals()、hashCode()、toString()は実装されている関数を使用します。
・スーパータイプが、openであり互換性のある型を返すcomponentN()を持つ場合、対応する関数が作成されスパータイプのcomponentN()をオーバーライドします。
スーパータイプの関数が互換性のないシグネチャ、もしくはfinalで宣言されている場合はオーバーライドできずにエラーを出力します。
・componentN()とcopy()関数の実装は禁止されています。

データクラスのプロパティ

上記の関数が作られるのはプライマリコンストラクタで宣言されているプラパティに対してです。
データクラスのボディでプロパティを宣言すると、そのプラパティに対する関数の自動生成はされません。

data class DataClass01(var name: String) {
    var age = 10
}

fun main() {
    val dataClass01 = DataClass01("TEST")
    dataClass01.age = 10
    
    val dataClass02 = DataClass01("TEST")
    dataClass02.age = 20
    
    println(dataClass01 == dataClass02) // 結果: true
    println("dataClass01.age = ${dataClass01.age}") // 結果: dataClass01.age = 10
    println("dataClass02.age = ${dataClass02.age}") // 結果: dataClass02.age = 20
}

データクラスのプライマリコンストラクタにはnameが、ボディにageが宣言されているため、equals()、hashCode()、toString()、componentN()、copy()はnameに対してのみ作成されます。
そのため「dataClass01 == dataClass02」ではnameの値のみを比較しているため、ageで異なる値を代入しているにもかかわらず、trueが返されます。

コピー

copy()関数は対象をそのままコピーすることも、一部のプロパティの値を変えて作成することも可能です。

data class DataClass01(var name: String, var age: Int)

fun main() {
    val dataClass01 = DataClass01("TEST", 10)
    val dataClass02 = dataClass01.copy(age=20)
    
    println(dataClass01.toString()) // 結果: DataClass01(name=TEST, age=10)
    println(dataClass02.toString()) // 結果: DataClass01(name=TEST, age=20)
}

データクラスと分解宣言

データクラスに作られるcomponentN()関数は分解宣言で使われます。

data class DataClass01(var name: String, var age: Int)

fun main() {
    val dataClass01 = DataClass01("TEST", 10)
    val (name, age) = dataClass01 // 分解宣言
    
    println(dataClass01.toString()) // 結果: DataClass01(name=TEST, age=10)
    println("dataClass01.name = ${name}") // 結果: dataClass01.name = TEST
    println("dataClass01.age = ${age}") // 結果: dataClass01.age = 10
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です