Kotlin 中数据 class 的等于方法

Equals method for data class in Kotlin

我有以下数据class

data class PuzzleBoard(val board: IntArray) {
    val dimension by lazy { Math.sqrt(board.size.toDouble()).toInt() }
}

我阅读了 Kotlin 中的数据 classes 免费获取 equals()/hashcode() 方法。

我实例化了两个对象。

val board1 = PuzzleBoard(intArrayOf(1,2,3,4,5,6,7,8,0))
val board2 = PuzzleBoard(intArrayOf(1,2,3,4,5,6,7,8,0))

但是,下面的陈述return仍然是错误的。

board1 == board2
board1.equals(board2)

在 Kotlin data classes 中,数组与其他 classes 一样,使用 equals(...) 进行比较,它比较数组引用,而不是内容。此行为描述为 here:

So, whenever you say

  • arr1 == arr2

  • DataClass(arr1) == DataClass(arr2)

  • ...

you get the arrays compared through equals(), i.e. referentially.

鉴于此,

val arr1 = intArrayOf(1, 2, 3)
val arr2 = intArrayOf(1, 2, 3)

println(arr1 == arr2) // false is expected here
println(PuzzleBoard(arr1) == PuzzleBoard(arr2)) // false too


要覆盖它并在结构上比较数组,您可以在数据 class 中使用 Arrays.equals(...) and Arrays.hashCode(...):

实现 equals(...)+hashCode()
override fun equals(other: Any?): Boolean{
    if (this === other) return true
    if (other?.javaClass != javaClass) return false

    other as PuzzleBoard

    if (!Arrays.equals(board, other.board)) return false

    return true
}

override fun hashCode(): Int{
    return Arrays.hashCode(board)
}

这段代码是IntelliJ IDEA针对非数据自动生成的classes.

另一个解决方案是使用 List<Int> 而不是 IntArray。列表在结构上进行比较,因此您不需要覆盖任何内容。

对于 Kotlin 中的 Data classes,如果两个对象的参数值相同,hashcode() 方法将生成和 return 相同的整数。

val user = User("Alex", 1)
val secondUser = User("Alex", 1)
val thirdUser = User("Max", 2)

println(user.hashCode().equals(secondUser.hashCode()))
println(user.hashCode().equals(thirdUser.hashCode()))

运行 此代码将 return TrueFalse 与我们创建 时一样secondUser 对象我们传递了与对象 user 相同的参数,因此为它们生成的 hashCode() 整数将相同。

另外,如果你要检查这个:

println(user.equals(thirdUser))

它会 return 错误。

根据 hashCode() 方法文档

open fun hashCode(): Int (source)

Returns a hash code value for the object. The general contract of hashCode is:

Whenever it is invoked on the same object more than once, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.

If two objects are equal according to the equals() method, then calling the hashCode method on each of the two objects must produce the same integer result.

有关详细信息,请参阅此讨论 here

在 Kotlin 中,equals()ListArray 之间的行为不同,您可以从下面的代码中看到:

val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2, 3)

val array1 = arrayOf(1, 2, 3)
val array2 = arrayOf(1, 2, 3)

//Side note: using a==b is the same as a.equals(b)

val areListsEqual = list1 == list2// true
val areArraysEqual = array1 == array2// false

List.equals() 检查两个列表是否具有相同的大小并且包含相同顺序的相同元素。

Array.equals() 只是进行实例引用检查。由于我们创建了两个数组,它们指向内存中的不同对象,因此不被认为是相等的。

从 Kotlin 1.1 开始,要实现与 List 相同的行为,您可以使用 Array.contentEquals().

来源:Array.contentEquals() docsList.equals() docs

Kotlin 实现:

override fun equals(other: Any?): Boolean {
    when (other) {
        is User -> {
            return this.userId == other.userId &&
                    this.userName == other.userName
        }
        else -> return false
    }
}