【问题标题】:Equals method for data class in KotlinKotlin中数据类的equals方法
【发布时间】:2016-09-28 05:02:40
【问题描述】:

我有以下数据类

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

我读到 Kotlin 中的数据类可以免费获得 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))

但是,以下语句仍然返回 false。

board1 == board2
board1.equals(board2)

【问题讨论】:

  • 评论永远不会太晚,因为数据类 equals 合同是在主构造函数中传递的参数的基础上生成的。例如,board1 = PuzzleBoard("Board", 20)board2 = PuzzleBoard("Board", 20) 将返回 trueboard1 == board2。在您的情况下,将根据数组内存地址生成相等的合同,这就是您得到错误的原因。

标签: arrays equals kotlin data-class


【解决方案1】:

Kotlin 实现:

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

【讨论】:

    【解决方案2】:

    在 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

    【讨论】:

      【解决方案3】:

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

      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()))
      

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

      如果你会检查这个:

      println(user.equals(thirdUser))
      

      它将返回 false。

      根据 hashCode() 方法文档

      open fun hashCode(): Int (source)
      

      返回对象的哈希码值。总承包合同 hashCode 是:

      只要在同一个对象上多次调用它,hashCode 方法必须始终返回相同的整数,前提是没有 对象上的 equals 比较中使用的信息已修改。

      如果两个对象根据equals()方法相等,则调用 两个对象中每一个的 hashCode 方法必须产生相同的 整数结果。

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

      【讨论】:

        【解决方案4】:

        在 Kotlin data 类的相等性检查中,数组,就像其他类一样,使用 equals(...) 进行比较,它比较的是数组引用,而不是内容。这种行为被描述为here

        所以,只要你说

        • arr1 == arr2

        • DataClass(arr1) == DataClass(arr2)

        • ...

        您可以通过equals() 比较数组,即引用。

        鉴于此,

        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
        


        要覆盖它并在结构上比较数组,您可以使用Arrays.equals(...)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 可以为非数据类自动生成的。

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

        【讨论】:

        • 有关在 Kotlin 中测试数组值相等性的更多信息,请参见此处:stackoverflow.com/q/35272761/1402641
        • 如果您想避免编写自己的 equals 方法,请考虑使用 List<Int> 而不是 IntArray。它不会像内存效率那么高,但除非您创建非常大的数组,否则影响将是微乎其微的。
        • 我对 Kotlin 了解不多,但使用 if(other !is thisClass) return false 会更好吗?那么下一行就不需要 as thisClass 了,因为编译器现在可以进行智能转换了,对吧?
        • 我怎样才能找到以及什么快捷方式(如果它在 IntelliJ 中不同)引导我执行此方法?
        • @ChadMx,哦,我真的误会你了。由于成员不是作为 Kotlin 源生成的,而是直接作为 JVM 字节码生成的,因此只能检查生成的字节码 see how。您将在数据类中找到生成的方法。
        猜你喜欢
        • 1970-01-01
        • 2018-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多