I'm seeing writing a test that I cannot assert two sealed classes with same "subclass" and same value under the hood are equal. They are distinct.
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()
}
}
}
This main function returns:
false
true
I do not really get why that behaviour.. I guess it is related to the nature of sealed classes it self and I'm not getting it?
Thanks in advance
CodePudding user response:
That's normal behaviour for any class - two different instances are not equal by default, because it checks for referential equality (i.e. the two references are pointing at the same object in memory).
class NormalClass(val value: String)
val a = NormalClass("foo")
val b = NormalClass("foo")
println(a == b)
> false
data class
es provide a default equals
and hashCode
implementation that ignores referential equality, and just compares the object type, and the values of the properties in the constructor
data class DataClass(val value: String)
val a = DataClass("foo")
val b = DataClass("foo")
println(a == b)
> true
A sealed class
is really just a special type that a class can belong to, which is mostly used for things like defining all the possible objects that have that type. It allows you to group disparate classes and objects together, and do things like exhaustive pattern matching (e.g. a when
clause operating on a MySealed
object can tell when you've checked all the possible members of that type)
Your A
class is a normal class, so two instances of it are not equal by default. If you made it an object
in MySealed
, there would only be one instance of it. In that sense, it can operate a little like an enum class
. A sealed class lets you mix and match these different types, with some benefits and drawbacks
You can just make A
a data class inside the sealed class, if you want them to match if they have the same value
, but also be a MySealed
CodePudding user response:
Kotlin Sealed classes do not override the default equals()
implementation from the Object
Java class. This means that the objects are compared using their reference, hence a1
and a2
are not equal.
Kotlin Data classes in their turn do override the equals()
method based on all properties declared in the primary constructor (read more about them at https://kotlinlang.org/docs/data-classes.html).