简体   繁体   中英

Scala match in equals method

I'm new to Scala, but have a decent Java background. My question is about overriding the equals method in Scala. The following example is from the Scala cookbook:

class Person (name: String, age: Int) {
    def canEqual(a: Any) = a.isInstanceOf[Person]
    override def equals(that: Any): Boolean =
        that match {
            case that: Person => that.canEqual(this) && this.hashCode == that.hashCode
            case _ => false
     }
}

My question is why we need

that.canEqual(this)

My understanding is that that code will only be executed if 'that' is a person. So, why the extra call to isInstanceOf?

that.canEqual(this) is not redundant. It is necessary in case that is an instance of a subclass of Person that has defined it's own equality (and it's own canEqual method).

this.canEqual(that) on the other hand would be redundant.

The main purpose is to ensure that the equality relation is valid in both directions between an instance of Person and potentially a subclass of Person that may have it's own implementation of equals.

Suppose I have:

 class Person(...) {
    ... as defined, but without the `that.canEqual(this)` call
 }

 class Nobody extends Person {
   // contrived, but valid definition
   override def equals (that: Any) = false 
   ... and some definition of hashCode that happens to produce same value
 }

 ...
 // then
 new Person(...) == new Nobody // true
 new Nobody == new Person(...) // false

 // breaks equals by not being symmetric

More detailed explanation link provided by pedrofurla in the comments: http://www.artima.com/pins1ed/object-equality.html

Two different objects from two separate classes can have the same hash code; you therefore cannot say that two objects are equal based on their hash code alone. For example, a Dog with yellow fur and a loud bark might have hashCode of 20011 because of the way a Dog defines hashCode ; a RocketShip designed to fly to Saturn might also have a hashCode of 20011 for a very unrelated reason. Clearly, these are two very different objects. If, however, two Dogs or two RocketShips have the same hash code then it is probably* safe to assume they're equivalent objects: it wouldn't make any sense to have to have two equivalent objects (eg, two Dogs with yellow fur and loud barks) have two different hash codes, and it wouldn't make sense to have two different objects of the same type (eg, one Dog with black fur, another with brown fur) have the same hash code. The isInstanceOf check lets you ensure that you're dealing with two objects of the same type: the hash code check allows you to quickly assess whether or not two objects should be equivalent.

(*: If there are a finite number of hash codes and an infinite combination of attributes producing unique Dogs , then there will inevitably be hash code collisions. Even the isInstanceOf check isn't sufficient, but is probably good enough for most cases and hence in the cookbook as an example.)

Edit: See here :

Pitfall #2: Changing equals without also changing hashCode. If two objects are equal according to the equals method, then calling the hashCode method on each of the two objects must produce the same integer result

In short, two equal objects must have the same hash code to fulfill the method's contract (but nowhere does it say that two objects with equal hash codes must be equal!)

Edit 2 As you have a Java background, you're likely used to seeing something of the following.

public boolean equals(Object other) {

   // I am a Dog. If they're not a dog, I can't be equal to them.
   if (!(other instanceof Dog)) 
      return false;

   // If the other dog's properties are equal to my own, then we're equal.
   if (...)
      return true;
   // If not, we're not equal.
   else
      return false;
 }

The code sample you've given is doing (roughly) the same thing, with the hashCode check substituting for an equality check.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM