data classで配列を使う時はequalsをオーバーライドしよう [Kotlin]
data classとは
data classは以下のようにクラスにdata
をつけて宣言することで、
コンストラクタで宣言されたプロパティを使ったequals/hashCode/toString関数などを自動生成してくれます。
data class Book( val title: String, val page: Int ) val book1 = Book("book", 100) val book2 = Book("book", 100) book1.toString() // => Book(title=book, page=100) book1 == book2 // => true
toString()
で返って来る文字列にプロパティの値が入っていたり、
==
(equalsが呼ばれる)を使った比較ができたりします。
data class内で配列を宣言した場合
↓のようにプロパティに配列型を宣言した場合にも、同様にequals()
などの関数が自動で生成されます。
data class Book( val title: String, val author: Array<String> ) val book1 = Book("book", arrayOf("Alice","Bob")) val book2 = Book("book", arrayOf("Alice","Bob")) book1.toString() // Book(title=book, author=[Alice, Bob]) book1 == book2 // false
しかし、先ほどとは違いbook1 == book2
の結果がfalseになってしまいます。
なぜ配列を使うと比較がうまくできないのか?
配列を使ったdata classをJavaにデコンパイルすると、
Array<String>
はString[]
に、data classのequals内の配列の比較はarray1.equals(array2)
と同等のコードになります。
Javaの配列型のequals()
メソッドは、要素の比較は行わず配列型のインスタンスが同じかどうかを判定するため、配列内の値が等しいだけではtrue
になりません。
対処法
equals()
メソッドをオーバーライドしてArrays#equlas()
を使うことでこの問題を解決することが可能です。
IntellijやAndroidStudioでKotlinPluginを入れている場合(最近のバージョンでは初めから入っています)は、Inspectionが表示され以下のようなequals()/hashCode()を自動生成することが可能になっています。
override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Book if (title != other.title) return false if (!Arrays.equals(author, other.author)) return false return true } override fun hashCode(): Int { var result = title.hashCode() result = 31 * result + Arrays.hashCode(author) return result }