What is the difference between “==” and equals(…) method? What is the difference between shallow comparison and deep comparison of objects?

When you are using a collection of objects e.g. using a java.util.Set of persist-able Hibernate objects etc. It is easy to implement these methods incorrectly and consequently your program can behave strangely and also is hard to debug. So, you can expect these questions in your interviews.

  • == [ shallow comparison ]

The == returns true, if the variable reference points to the same object in memory. This is a “shallow comparison”.

  • equals( ) [deep comparison ]

The equals() – returns the results of running the equals() method of a user supplied class, which compares the attribute values. The equals() method provides “deep comparison” by checking if two objects are logically equal as opposed to the shallow comparison provided by the operator ==.
If equals() method does not exist in a user supplied class then the inherited Object class’s equals() method is run which evaluates if the references point to the same object in memory. The object.equals() works just like the “==” operator (i.e shallow comparison).
Overriding the Object class may seem simple but there are many ways to get it wrong, and consequence can be unpredictable behavior.

String str = new String(“ABC”); //Wrong. Avoid this because a new String instanceNote: String assignment with the “new” operator follow the same rule as == and equals( ) as mentioned above.

//is created each time it is executed.

Variation to the above rule:
The “literal” String assignment is shown below, where if the assignment value is identical to another String assignment value created then a new String object is not created. A reference to the existing String object is returned.

String str = “ABC”; //Right because uses a single instance rather than
//creating a new instance each time it is executed.

Let us look at an example:

public class StringBasics {
    public static void main(String[] args) {
        String s1 = new String("A"); //not recommended, use String s1 = "A"
        String s2 = new String("A"); //not recommended, use String s2 = "A"
        //standard: follows the == and equals() rule like plain java objects.
        if (s1 == s2) { //shallow comparison
            System.out.println("references/identities are equal"); //never reaches here
        }
        if (s1.equals(s2)) { //deep comparison
            System.out.println("values are equal"); // this line is printed
        }
        //variation: does not follow the == and equals rule
        String s3 = "A"; //goes into a String pool.
        String s4 = "A"; //refers to String already in the pool.
        if (s3 == s4) { //shallow comparison
            System.out.println("references/identities are equal"); //this line is printed
        }
        if (s3.equals(s4)) { //deep comparison
            System.out.println("values are equal"); //this line is also printed
        }
    }
}

Design pattern: String class is designed with Flyweight design pattern. When you create a String constant as shown above in the variation, (i.e. String s3 = “A”, s4= “A”), it will be checked to see if it is already in the String pool. If it is in the pool, it will be picked up from the pool instead of creating a new one. Flyweights are shared objects and using them can result in substantial performance gains.

Tagged . Bookmark the permalink.

Leave a Reply