Overriding equals() and hashCode()

Figure 451. Shape.equals() Slide presentation Create comment in forum
public abstract class Shape {
  ...
  @Override  public boolean equals(final Object o) {
    if (o instanceof Shape ) {
      final Shape other = (Shape) o; 
      return x == other.x && y == other.y; 
    } else {
      return false; 
    } ...

Promise: The current method overrides a superclass method.

Other instance is a Shape object?

Casting other object to class Shape.

Return true if and only if both center coordinate pairs are equal.

Other object distinct from class Shape.


Figure 452. Rectangle.equals() Slide presentation Create comment in forum
public class Rectangle extends Shape {
  ...
  @Override public boolean equals(final Object o) {
    if (o instanceof Rectangle) {
      final Rectangle other = (Rectangle) o;
      return super.equals(o)  &&
             width == other.width && height == other.height ;
    } else {
      return false;
    } ...

Including superclass method Shape.equals().

Return true if and only if both width and height pairs are equal.


exercise No. 159

Let me in, please! Create comment in forum

Q:

Consider the following snippet:

try (final Scanner scan = new Scanner(System.in)) {
  do {
    System.out.print("Please enter password: ");
    final String password = scan.nextLine();
    if (password == "secret") {
      break;  // Leave enclosing do ... while loop
    } else {
      System.out.println("Sorry, please try again");
    }
  } while (true);
  System.out.println("You made it!");
  // ...
}

Describe the above code's intended behaviour. Will it succeed? Execute the above code and provide a clue for correcting the underlying flaw.

A:

The user is being asked for a password. Only when entering "secret" access shall be granted.

Unfortunately comparing the user's input and the corresponding password is seriously flawed:

...
  if (password == "secret")
...

On execution the string literal "secret" will be represented as a String object in memory. Each new user input string will be represented as a different String object in memory as well.

Unfortunately the usual == operator only works as expected for the eight built in primitive Java types. With respect to class instances a variable holds a reference to an object rather than the object itself. Applying the == operator compares for object identity rather than object equality.

Two different String instances albeit being different object instances may off course be equal with respect to their payload namely the strings they both represent. Comparing for object equality rather than for object identity in Java requires overriding the Object.equals(Object o) method. This override does exist in class String. Within the given context we may thus simply use String.equals(Object o):

try (final Scanner scan = new Scanner(System.in)) {
  do {
    System.out.print("Please enter password: ");
    final String password = scan.nextLine();
    if (password.equals("secret")) {
      break;  // Leave enclosing do ... while loop
    } else {
      System.out.println("Sorry, please try again");
    }
  } while (true);
  System.out.println("You made it!");
  // ...
}

exercise No. 160

Why does == work for enum instances? Create comment in forum

Q:

The preceding exercise Let me in, please! told us to override Object.equals(Object o) when comparing for the equality of different objects.

With respect to enum instances there seems to be an exception to the rule e.g.:

Day day = Day.Saturday;

// Sufficient using operator == ?
if (day == Day.FRIDAY) ... 

// Or do we require equals?
if (day.equals(Day.FRIDAY)) ...

Do we thus require an equals(Object o) method for comparisons? Give a precise explanation.

A:

In case of enum instances using the == operator is sufficient. Due to the way enum's are being constructed instance creation is being limited to the underlying enum's scope by its implicitly private declared constructor. It is thus impossible to create new instances outside the respective enum's scope.

Therefore object identity and equality of values are being guaranteed to match exactly for two arbitrary instances belonging to the same enum class:

MyEnum e1 = ..., e2 = ...;          // MyEnum representing some enum type

final boolean
  objectIdentity = (e1 == e2),      // Both boolean values will
  objectEquality = e1.equals(e2);   // always be equal.

As an aside: In case of null values using the == operator avoids java.lang.NullPointerException problems:

Day day = null;

if (day == Day.FRIDAY) ...      // Just different, no problems

if (day.equals(Day.FRIDAY)) ... // Oops: NPE approaching ...