作成日 2025/01/29
最終更新日 2025/01/29

data class について

背景

stateFlowとdata class を利用して画面に表示する内容を管理していました。ですが、data class の詳しいことを知らないなと思ったので色々調べてみます。

そもそもデータクラスとは?

とりあえず公式ページ[1]を確認します。

Data classes in Kotlin are primarily used to hold data.
For each data class, the compiler automatically generates additional member functions that allow you to print an instance to readable output, compare instances, copy instances, and more.

冒頭の引用です。一部改行を入れています。
データを保持するためのクラスで、コンパイラがメンバ関数を自動で作成してくれるそうです。便利ですね。これらのメソッドは、プライマリコンストラクタのプロパティに関して作成されます。
……ところでメソッドではなくメンバ関数と呼ぶんですね。また関数とメソッドの違いがわからなくなってしまいました。

自動生成されるメソッド

各メソッドの内容を確認していきます。

equals() / hash()

インスタンスの等価性を確認するのメソッドです。
javaの話[2]ですが、equalsで利用する値と紐づけた唯一の値を作成する必要があるそうです。自作する場合はかなりめんどくさそうなので、自動で生成してくれるのはありがたいです。
データクラスの場合、プライマリコンストラクタ内のパラメータが等しければ同値となります。
今回利用したクラスとテストは以下の通りです。正し、一部省略しています。リポジトリはこちらです

class User(
    var name: String,
    var age:Int,
)

data class UserData(
    var name: String,
    var age: Int,
)
class DataClassTest {
    private val name = "Taro"
    private val age = 20

    @Test
    fun equal() {
        val man1 = User(
            name = name,
            age = age,
        )

        val man2 = User(
            name = name,
            age = age,
        )

        val hash1 = man1.hashCode()
        val hash2 = man2.hashCode()

        assertNotEquals(man1, man2)
        assertNotEquals(hash1,hash2)

        man2.age++
        val hash3 = man2.hashCode()
        assertEquals(hash2,hash3)
    }

    @Test
    fun equalVar() {
        val man1 = UserData(
            name = name,
            age = age,
        )
        val man2 = UserData(
            name = name,
            age = age,
        )

        val hash1 = man1.hashCode()
        val hash2 = man2.hashCode()

        assertEquals(man1, man2)
        assertEquals(hash1,hash2)

        man2.age++
        val hash3 = man2.hashCode()

        assertNotEquals(hash2,hash3)
        assertNotEquals(man1,man2)
    }
}
    

importを省略したテストコードです。テスト結果はOKになるものです。
通常のクラスは異なるインスタンスは「等しくない」と判定されます。
対してデータクラスは異なるインスタンスでもプライマリコンストラクタのプロパティが等しければ「等しい」と判定されます。
逆に言うと、プライマリコンストラクタに含まれないプロパティは異なっていても同値になります。公式ページ(この辺)に書いてあります。
また、コンストラクタに含まれるプロパティの値を変更した場合、通常のクラスではハッシュ値は変わりませんが、データクラスの場合はハッシュ値が変わり等しいインスタンスと判定されなくなります。

toString()

挙動に対して、特に説明することはありません。
データクラス以外のクラスで、toString()をoverrideせずに呼び出した際に表示される物は以下の文字列です[3](この辺)。

getClass().getName() + '@' + Integer.toHexString(hashCode())

前半がクラス名であることは予想がついていましたが、後半はhash値の16進表示だったのですね、1つ賢くなりました。 Kotlinで同じレベルのドキュメントを探したかったんですが、toString()のページ[4]くらいしか見つけられませんでした、残念。
なんにせよ、自動でオーバーライドして見やすい形で表示してくれるので助かります。

componentN()

これも挙動に対して特に説明することはありません。N番目の要素を利用するためのメソッドです。
このcomponentNは分解宣言で利用されている様です[5]
ただ、スコープ関数のapplyでアクセスした方が順番を気にしなくていいのでよいのでは? と個人的には思います。Kotlinはjavaと違い名前付き引数を使えるので引数の順番を意識しなくてよいというのがメリットの1つではあるので。

copy()

一部の値だけを変更したいときに利用する関数です。公式ページ[1](この辺)。自身のプライマリコンストラクタと同じ引数を取り、自身が持っているプロパティをデフォルト引数として利用しています。
内容を確認するまで確証はなかったのですが、コンストラクタをきちんと呼び出している様です。
varを利用しているならcopyを利用せずに値を変更できます。上記のtestコードでもcopyを利用せずに値を変更しています。
ただ、stateFlowを利用して画面に描画するならcopyを利用した方が便利です。

まとめ

以上、データクラスについて調べてみました。
uiSateとしてdata class を利用する方法も割と主流っぽい[6][7][8]ので合わせて調べたいですね。ここに書くには少しdata class から遠いと思いました。
copy内部でも少し触れてますが、stateFlowついても整理したいと思います。もともと冒頭にも書いた通り、stateFlowも使っているので。
とまぁ、他にやりたいことも見つかったので、今回はこの辺でお終いです。ではまた。

参考

  1. 『Data classes』Kotlin docs
    https://kotlinlang.org/docs/data-classes.html
    (2025/01/29)
  2. 『Javaを陰から支えるhashCodeとは?hashCodeの仕組みと実装方法』 ENGINEER.CLUB
    https://www.bold.ne.jp/engineer-club/java-hashcode
    (2025/01/28)
  3. 『JavaのtoStringメソッドとは?文字列に変換したい時のtoStringの使い方【valueOfとの違いも解説】』 ENGINEER.CLUB
    https://www.bold.ne.jp/engineer-club/java-tostring
    (2025/01/28)
  4. 『toString』 Kotlin docs
    https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/to-string.html
    (2025/01/29)
  5. 『Destructuring declarations』 Kotlin docs
    https://kotlinlang.org/docs/destructuring-declarations.html
    (2025/01/29)
  6. 『UI 状態生成』 Android Developers
    https://developer.android.com/topic/architecture/ui-layer/state-production?hl=ja
    (2025/01/29)
  7. 『UIStateの基本とさまざまな工夫』Qiita
    https://qiita.com/mi_iroha/items/18403098b4ccefc003e6
    (2025/01/29)
  8. 『UI状態をdata classで管理する時の大体のお決まりっぽいもの』 Qiita
    https://qiita.com/FalconFlat/items/b2c4ed3c2e2e00e97beb
    (2025/01/29)