Reputation: 750
Consider the following code:
import scala.collection.mutable
case class A(b: Int) {
override def equals(obj: Any): Boolean = {
println("called")
obj match {
case o: A => b == o.b
case _ => false
}
}
}
val set = mutable.Set.empty[A]
val a1 = A(1)
set.add(a1)
println(set.contains(A(1)))
println(set.contains(A(2)))
Why the second call of set.contains
doesn't print out "called"? Can someone explain how set identify two objects being equal?
Upvotes: 0
Views: 1805
Reputation: 8529
As @LuisMiguelMejíaSuárez mentioned in the comments, A mutable Set
is backed by a HashSet
. It is well elaborated at What issues should be considered when overriding equals and hashCode in Java?
Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
This is because hashCode
is a prior check, which when fails equals
will definitely fail as well.
From What code is generated for an equals/hashCode method of a case class? we can conclude that for case classes hashCode
and equals
are overridden for case classes, using productPrefix
which means the first set of elements in the case class. For example, if we have:
case class c(a: A)(b: B)
The hashCode
and equals
will be calculated only based on a
. In your case, the hasCode
method is calculated based on gender
, which is different for Person(1)
and Person(2)
. Therefore there is no need to check equals
, which suppose to fail as well.
A tip from What issues should be considered when overriding equals and hashCode in Java?
In practice:
If you override one, then you should override the other.
Use the same set of fields that you use to compute equals() to compute hashCode().
Upvotes: 2