Kotlin 密封了 类 和 hashcode/equals

Kotlin sealed classes and hashcode/equals

我正在编写一个测试,我无法断言两个具有相同“子类”和相同值的密封 类 是相等的。它们是不同的。

fun main() {

    val a1 = MySealed.A("foo")
    val a2 = MySealed.A("foo")

    System.out.println(a1 == a2)
    
    val a3 = MySealedWithEqualsAndHashCodeOverriden.A("foo")
    val a4 = MySealedWithEqualsAndHashCodeOverriden.A("foo")
    
    System.out.println(a3 == a4)
    
}

sealed class MySealed(val value: String) {
    class A(value: String) : MySealed(value)
}

sealed class MySealedWithEqualsAndHashCodeOverriden(val value: String) {
    class A(value: String) : MySealedWithEqualsAndHashCodeOverriden(value) {
         override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false
            return true
        }

        override fun hashCode(): Int {
            return javaClass.hashCode()
        }
    }
}

这个主要函数returns:

false
true

我真的不明白为什么会出现这种行为。我想这与密封的性质有关 类 它本身而我不明白?

提前致谢

Kotlin Sealed classes 不会覆盖 Object Java class 中的默认 equals() 实现。这意味着使用对象的引用来比较对象,因此 a1a2 不相等。

Kotlin Data classes 会根据主构造函数中声明的所有属性重写 equals() 方法(在 https://kotlinlang.org/docs/data-classes.html 阅读更多关于它们的信息)。

这是任何 class 的正常行为 - 默认情况下两个不同的实例不相等,因为它检查引用相等性(即两个引用指向内存中的同一个对象)。

class NormalClass(val value: String)

val a = NormalClass("foo")
val b = NormalClass("foo")
println(a == b)

> false

data classes提供了默认的equalshashCode实现,忽略引用相等,只比较对象类型,构造函数中的属性值

data class DataClass(val value: String)

val a = DataClass("foo")
val b = DataClass("foo")
println(a == b)

> true

A sealed class 实际上只是一个特殊的 type 可以属于 class,主要用于定义所有可能的对象有那种类型。它允许您将不同的 classes 和对象组合在一起,并执行诸如详尽模式匹配之类的操作(例如,在 MySealed 对象上运行的 when 子句可以告诉您何时检查了所有该类型的可能成员)

你的Aclass是一个普通的class,所以它的两个实例在默认情况下是不相等的。如果您将它设为 MySealed 中的 object,那么它只会有一个实例。从这个意义上说,它的运作有点像 enum class。密封的 class 让您可以混合搭配这些不同的类型,有一些优点和缺点

你可以只做A一个数据class在密封的class里面,如果你想让它们匹配如果它们有相同的value,也可以一个 MySealed