4.5. Comparing objects for equality

[3.2] Test equality between Strings and other objects using == and equals()

In section 4.1, you saw how the class String defined a set of rules to determine whether two String values are equal and how these rules were coded in the method equals. Similarly, any Java class can define a set of rules to determine whether its two objects should be considered equal. This comparison is accomplished using the method equals, which is described in the next section.

4.5.1. The method equals in the class java.lang.Object

The method equals is defined in class java.lang.Object. All the Java classes directly or indirectly inherit this class. Listing 4.2 contains the default implementation of the method equals from the class java.lang.Object.

Listing 4.2. Implementation of equals method from class java.lang.Object
public boolean equals(Object obj) {
    return (this == obj);
}

As you can see, the default implementation of the equals method only compares whether two object variables refer to the same object. Because instance variables are used to store the state of an object, it’s common to compare the values of the instance variables to determine whether two objects should be considered equal.

4.5.2. Comparing objects of a user-defined class

Let’s work with an example of the class BankAccount, which defines two instance variables: acctNumber of type String, and acctType of type int. The equals method compares the values of these instance variables to determine the equality of two objects of the class BankAccount.

Here’s the relevant code:

Let’s verify the working of this equals method in the following code:

prints false because the value of the reference variables b1 and b2 don’t match. prints true because the values of the reference variables b2 and b3 match each other. passes an object of type String to the method equals defined in the class Bank-Account. This method returns false if the method parameter passed to it is not of type BankAccount. Hence, prints false.

Even though the following implementation is unacceptable for classes used in the real world, it’s still correct syntactically:

class BankAccount {
    String acctNumber;
    int acctType;
    public boolean equals(Object anObject) {
        return true;
    }
}

The previous definition of the equals method will return true for any object that’s compared to an object of the class BankAccount because it doesn’t compare any values. Let’s see what happens when you compare an object of the class String with an object of class BankAccount and vice versa using equals():

In the preceding code, prints true, but prints false. The equals method in the class String returns true only if the object that’s being compared to is a String with the same sequence of characters.

Exam Tip

In the exam, watch out for questions about the correct implementation of the equals method (refer to section 4.5.4) to compare two objects versus questions about the equals methods that simply compile correctly. If you’d been asked whether equals() in the previous example code would compile correctly, the correct answer would be yes.

4.5.3. Incorrect method signature of the equals method

It’s a common mistake to write an equals method that accepts an instance of the class itself. In the following code, the class BankAccount doesn’t override equals(); it overloads it:

Although the previous definition of equals() may seem to be flawless, what happens when you try to add and retrieve an object of the class BankAccount (as shown in the preceding code) from an ArrayList? The method contains defined in the class ArrayList compares two objects by calling the object’s equals method. It does not compare object references.

In the following code, see what happens when you add an object of the class Bank-Account to an ArrayList and then try to verify whether the list contains a BankAccount object with the same instance variable’s values for acctNumber and acctType as the object being searched for:

and define objects b1 and b2 of the class BankAccount with the same state. adds b1 to the list. compares the object b2 with the objects added to the list.

An ArrayList uses the method equals to compare two objects. Because the class BankAccount didn’t follow the rules for correctly defining (overriding) the method equals, ArrayList uses the method equals from the base class Object, which compares object references. Because the code didn’t add b2 to list, it prints false.

What do you think will be the output of the previous code if you change the definition of the method equals in the class BankAccount so that it accepts a method parameter of type Object? Try it for yourself!

Exam Tip

The method equals defines a method parameter of type Object, and its return type is boolean. Don’t change the name of the method, its return type, or the type of method parameter when you define (override) this method in your class to compare two objects.

4.5.4. Contract of the equals method

The Java API defines a contract for the equals method, which should be taken care of when you implement it in any of your classes. I’ve pulled the following contract explanation directly from the Java API documentation:[1]

1

The Java API documentation for equals can be found on the Oracle site: http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals(java.lang.Object).

The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals() comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

As per the contract, the definition of the equals method that we defined for the class BankAccount in an earlier example violates the contract for the equals method. Take a look at the definition again:

public boolean equals(Object anObject) {
    return true;
}

This code returns true, even for null values passed to this method. According to the contract of the method equals, if a null value is passed to the equals method, the method should return false.

Exam Tip

You may get to answer explicit questions on the contract of the equals method. An equals method that returns true for a null object passed to it will violate the contract. Also, if the equals method modifies the value of any of the instance variables of the method parameter passed to it, or of the object on which it is called, it will violate the equals contract.

The hashCode() method

A lot of programmers are confused about the role of the method hashCode in determining the equality of objects. The method hashCode is not called by the equals method to determine the equality of two objects. Because the hashCode method is not on the exam, I’ll discuss it quickly here to ward off any confusion about this method.

The method hashCode is used by the collection classes (such as HashMap) that store key-value pairs, where a key is an object. These collection classes use the hashCode of a key to search efficiently for the corresponding value. The hashCode of the key (an object) is used to specify a bucket number, which should store its corresponding value. The hashCode values of two distinct objects can be the same. When these collection classes find the right bucket, they call the equals method to select the correct value object (that shares the same key values). The equals method is called even if a bucket contains only one object. After all, it might be the same hash but a different equals, and there is no match to get!

According to the Java documentation, when you override the equals method in your class, you should also override the hashCode method. If you don’t, objects of your classes won’t behave as required if they’re used as keys by collection classes that store key-value pairs. This method is not discussed in detail in this chapter because it isn’t on the exam. But don’t forget to override it with the method equals in your real-world projects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.140.68