提问者:小点点

如何在kotlin中实现equals/hashcode?


我在kotlin中搜索equals/hashcode

我了解等于和 (==) 在数据类中工作正常,但对于常规类,我想我们应该覆盖等于和哈希码方法:

class GroupWithData {

    var group: Group? = null

    var data: List<Data>? = null


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

        other as GroupWithData

        if (group!= other.group) return false
        if (data!= other.data) return false

        return true
    }

    override fun hashCode(): Int {
        var result = group?.hashCode() ?: 0
        result = 31 * result + (data?.hashCode() ?: 0)
        return result
    }

但是当我尝试等于两个列表时,它不起作用。

PS:组和数据类是“数据类”


共1个答案

匿名用户

检查data class Data的内容:它是否覆盖equalsData类的任何成员是否属于非原始类型并覆盖equals?有关更多解释和示例,请进一步阅读。

你完全正确,对于常规类,如果我们想通过值而不是引用来比较两个对象,我们必须重写< code>equals和< code>hashCode函数。< code>equals的实现可以是您喜欢的任何东西。这完全取决于您的应用程序的业务逻辑,以及在您的特定情况下什么被认为是“相等”的。

您拥有的实现实际上已经足够好了。基本上检查身份(也称为通过引用进行比较,< code>=== Kotlin操作符),检查< code>other是否属于同一个实例类,任何进一步的工作都取决于业务逻辑。

hashCode函数的实现可能使用您在equals函数中比较过的相同成员,但使用类的其他成员也可以。

注意:通常认为最好的做法是覆盖函数等于哈希代码。即使哈希代码不直接在您的代码中使用,它也可以在您可以使用的库的某些实现下使用。如果两个对象相等,则它们的哈希代码也必须相等。如果对象未更改,哈希代码必须保持不变。

我不太确定,但问题可能出在Data数据类或其成员的值中。

我用基元类型和<code>数据类data</code>运行了两个简单的测试,看起来如下:

测试#1

    var list1: List<Int> = listOf(1,2,3,4)
    var list2: List<Int> = arrayListOf(1,2,3,4)
    var list3: List<Int> = LinkedList<Int>().also { it.addAll(listOf(1,2,3,4)) }

    fun equals(): Boolean {
        return list1 == list3 && list1 == list2 && list2 == list3
    }

    println(equals())

测试#2

    data class Data(var i: Int = 0)
    var list1: List<Data> = listOf(Data(1),Data(2),Data(3),Data(4))
    var list2: List<Data> = arrayListOf(Data(1),Data(2),Data(3),Data(4))
    var list3: List<Data> = LinkedList<Data>().also { it.addAll(listOf(Data(1),Data(2),Data(3),Data(4))) }

    fun equals(): Boolean {
        return list1 == list3 && list1 == list2 && list2 == list3
    }

    println(equals())

在这两种情况下,印刷品都是真实的。这是真的,因为在 Kotlin 文档之后它说:

如果两个列表在相同的位置具有相同的大小和结构上相等的元素,则它们被认为是相等的。

文件参考。

这里描述了结构上的平等。

现在,这里是修改后的< code>Data类,在它的< code>equals实现中发生了一些奇怪的事情:

    data class Data(var i: Int = 0) {
        // Custom equals!
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as Data

            return (i + other.i) % 2 == 1
        }
    }

如果尝试将相同的列表与按相同顺序添加的Data对象进行比较,则列表将不相等,因为两个Data\的比较有时会返回false

如果< code>Data类包含另一个非原始类型,并且它的< code>equals方法没有为实际相等的对象返回< code>true,这也可能是问题所在。如此等等。