I wonder why the equal method (==) does not work as expected.
Is there any way to fix the commented section in the code below?
As you can see p1 and p2 are not equals, neither reference nor value. So why p1 == p2 is true?!
object Main {
@JvmStatic
fun main(args: Array<String>) {
val f1 = Foo(1)
Thread.sleep(3) // to set a different value in parent of f2
val f2 = Foo(1)
val p1 = (f1 as Parent)
val p2 = (f2 as Parent)
println(p1 == p2) // true
println(p1.b == p2.b) // false
}
}
data class Foo(val a: Int) : Parent("$a-${System.currentTimeMillis()}")
sealed class Parent(val b: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Parent
if (b != other.b) return false
return true
}
override fun hashCode(): Int {
return b.hashCode()
}
}
CodePudding user response:
The reason this doesn't behave as you expect is because a data class
automatically provides you with an implementation of equals()
, one that checks (only) the values of the properties specified in its constructor.
So your data class Foo(val a: Int)
gets an equals()
that checks only the value of a
, overriding that in the Parent
class.
In general, data class
es are simple value holders, whose value is characterised entirely by those properties, and so the automatically-generated equals()
(and hashCode()
and toString()
and copy()
and componentX()
methods) make good sense. If that doesn't apply, a data class
might not be a good fit for your case.
CodePudding user response:
There is one solution, and you have to override the equals and hashCode method explicitly in the Foo class. Then it will work fine.
object Main {
@JvmStatic
fun main(args: Array<String>) {
val f1 = Foo(1)
Thread.sleep(3)
val f2 = Foo(1)
val p1 = (f1 as Parent)
val p2 = (f2 as Parent)
println(p1 == p2) // false
println(p1.b == p2.b) // false
}
}
data class Foo(val a: Int) : Parent("$a-${System.currentTimeMillis()}") {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
if (!super.equals(other)) return false
other as Foo
if (a != other.a) return false
return true
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result a
return result
}
}
sealed class Parent(val b: String) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Parent
if (b != other.b) return false
return true
}
override fun hashCode(): Int {
return b.hashCode()
}
}