データクラス
Kotlinのデータクラスは、主な目的がデータの保持であるようなクラスの事です。 データクラスはインスタンスを人間に読めるような形式で出力したり、 インスタンスを比較したり、インスタンスをコピーしたり、そのほか様々なメンバ関数が自動でついてきます。
データクラスはdata
でマークされます:
data class User(val name: String, val age: Int)
コンパイラは自動的に、プライマリコンストラクタで宣言されたすべてのプロパティから、次のメンバを派生します:
equals()
/hashCode()
のペア、"User(name=John, age=42)"
形式のtoString()
、- 宣言した順番でプロパティに対応する
componentN()
関数、 copy()
関数(下記参照)。
生成されたコードの一貫性と意味のある動作を保証するために、 データクラスは、次の要件を満たさなければなりません:
- プライマリコンストラクタは、少なくとも1つのパラメータを持っている必要があります。
- すべてのプライマリコンストラクタのパラメータは、
val
またはvar
としてマークする必要があります。 - データクラスは、 abstract, open, sealed または inner にすることはできません。
さらに、メンバの継承に関連して、生成されるデータクラスのメンバは以下のルールに従います:
.equals()
,.hashCode()
,.toString()
の明示的な実装がデータクラスの本体にあるか、基底クラスにfinal
の実装があれば、これらの関数は生成されず、すでにある実装が使われます。- 基底型が
.componentN()
をopen
で定義してあって戻りの型が互換性があれば、生成される対応する関数は基底クラスのoverrideとして実装されます。また、シグニチャが互換性が無かったりfinalだたりしてoverride出来ない時は、エラーとして報告されます。 .componentN()
や.copy()
を明示的に実装する事は禁止されています。
データクラスは他のクラスを継承する事が出来ます(sealedクラスに例があります)。
JVM上で、生成されたクラスがパラメータなしのコンストラクタを持つ必要がある場合は、 すべてのプロパティのデフォルト値を指定する必要があります(コンストラクタを参照してください)。
data class User(val name: String = "", val age: Int = 0)
クラス本体に宣言されたプロパティ
コンパイラが自動生成に使うのはプライマリコンストラクタに含まれているプロパティだけです。 だからあるプロパティを自動生成から除外したければ、 クラスの本体に実装すればいいでしょう:
data class Person(val name: String) {
var age: Int = 0
}
この例では、name
プロパティだけが .toString()
、 .equals()
、 .hashCode()
、 .copy()
の実装で使われて、
コンポーネント関数も.component1()
だけです。
age
プロパティが.toString()
、 .equals()
、 .hashCode()
、 .copy()
の実装で使われない理由は、
age
プロパティがクラス本体に宣言されているからです。
もし二つのPerson
オブジェクトが異なるage(訳注:年齢)でありながらname
が同じなら、
両者は等価として扱われます。
これは.equals
関数がname
の等価(equality)チェックしかしないからです。
例えば:
コピー
オブジェクトをコピーするには.copy()
関数が使えます。
プロパティの いくつか を変更し、残りをそのままにしてオブジェクトをコピーする、という事も出来ます。
User
クラスの場合、その実装は次のようになります。
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
これを用いて、次のように書くことができます:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
データクラスと分解宣言 (Destructuring Declarations)
データクラスのために生成された コンポーネント関数 は、分解宣言(destructuring declaration)で使用できます。
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, 年齢は $age 歳")
// Jane, 年齢は 35 歳
標準データクラス
標準ライブラリは、 Pair
と Triple
を提供します。
ですがほとんどの場合、プロパティに意味のある名前を提供することによりコードが読みやすくなるため、
データクラスを使う方がより良い設計上の選択です。