== vs equals()

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • == is an operator that compares Memory References (do these two variables point to the exact same object in RAM?).
  • .equals() is a method that compares Value Equality (do these two distinct objects contain the exact same data?).
  • For primitives (int, boolean), == compares their actual values. For Objects (String, Integer), always use .equals().

Concept

When you create a new Object in Java using the new keyword, the JVM allocates memory on the Heap and returns a reference (a pointer) to that memory location.

If you use == between two Objects, Java simply checks if their memory pointers are identical. It does not look inside the object to see what data it holds.
If you use .equals(), Java executes the equals() method defined in the class. The String class, for example, overrides this method to loop through every character in the string and verify they match, regardless of where they are stored in memory.

Note: If a class does not explicitly override .equals(), it inherits the default implementation from java.lang.Object, which internally just does ==!

Examples

public class EqualityDemo {
    public static void main(String[] args) {
        
        // 1. PRIMITIVES (Use ==)
        int a = 5;
        int b = 5;
        System.out.println(a == b); // TRUE
        
        // 2. STRINGS (The Tricky Part)
        // Literals go into the String Pool. Both point to the exact same memory!
        String s1 = "Hello";
        String s2 = "Hello";
        System.out.println(s1 == s2);      // TRUE (Same memory reference)
        System.out.println(s1.equals(s2)); // TRUE (Same value)
        
        // Using 'new' forces a brand new object on the Heap.
        String s3 = new String("Hello");
        System.out.println(s1 == s3);      // FALSE (Different memory reference!)
        System.out.println(s1.equals(s3)); // TRUE (Same value!)
        
        // 3. CUSTOM OBJECTS
        Person p1 = new Person("Alice");
        Person p2 = new Person("Alice");
        
        System.out.println(p1 == p2); // FALSE
        // This will be FALSE unless Person explicitly overrides the equals() method!
        System.out.println(p1.equals(p2)); 
    }
}

Interview Questions

Q: What happens if you compare Integer wrappers using ==?
A: This is a massive trap in Java. Because of the Integer Cache, comparing Integer wrappers with == can yield wildly inconsistent results.

Integer x = 100;
Integer y = 100;
System.out.println(x == y); // TRUE! (Cached values -128 to 127 point to same memory)

Integer a = 500;
Integer b = 500;
System.out.println(a == b); // FALSE! (Outside cache, brand new objects are created)

Always use .equals() for wrapper classes!

Q: Why must you override hashCode() if you override equals()?
A: The contract of java.lang.Object strictly states that if two objects are equal according to the equals() method, they must have the exact same integer returned by their hashCode() method.
If you override equals() to make two Person objects equal based on their name, but forget to override hashCode(), they will have different hash codes. If you put them in a HashSet or HashMap, the collection will use the hash code to place them in different buckets, completely breaking the collection (it will store duplicate people and fail to retrieve them).