Hiprup

What is the difference between the == operator and the equals() method in Java?

The == operator performs reference comparison for objects — it returns true only when two variables point to the same object in memory — while for primitives (int, char, boolean) it compares actual values. The equals() method performs content (logical) comparison when a class overrides it, as String, Integer, and the collection classes do.

By default, equals() in the Object class simply uses ==, so custom classes must override it to compare state meaningfully.

  • Reference vs content== asks "same object?", while an overridden equals() asks "same data?".

  • String pool caveat — identical string literals share one pooled object, so == can appear to work, but new String("x") creates a separate object and breaks it; always use equals() for strings.

  • equals()/hashCode() contract — objects equal by equals() must return the same hash code, or HashMap<String, Integer> and HashSet lookups misbehave.

  • Null safety — calling equals() on a null reference throws NullPointerException; prefer Objects.equals(a, b) or "expected".equals(actual).

  • Test-automation practice — TestNG's Assert.assertEquals() relies on equals(); comparing driver.getTitle() or getText() results with == fails even when the text matches, because WebDriver returns a new String object.

Key terms: reference comparison, content comparison, Object.equals(), string pool, hashCode() contract, Objects.equals(), NullPointerException

import java.util.Objects;

public class EqualsVsDoubleEquals {
    public static void main(String[] args) {
        String a = "selenium";
        String b = "selenium";              // reused from the String pool
        String c = new String("selenium");  // new object on the heap

        System.out.println(a == b);         // Output: true  (same pooled object)
        System.out.println(a == c);         // Output: false (different objects)
        System.out.println(a.equals(c));    // Output: true  (same content)

        Integer x = 1000;
        Integer y = 1000;
        System.out.println(x == y);         // Output: false (outside Integer cache -128..127)
        System.out.println(x.equals(y));    // Output: true

        int p = 1000, q = 1000;
        System.out.println(p == q);         // Output: true  (primitives compare values)

        String actual = null;
        System.out.println(Objects.equals("selenium", actual)); // Output: false (null-safe, no NPE)
    }
}

The two string literals share one interned object from the string pool, so == returns true for them, but new String("selenium") allocates a distinct heap object, making == false while equals() still returns true because the characters match. The Integer example shows that autoboxed values outside the cached range -128 to 127 get distinct wrapper objects, so == returns false even though equals() passes, whereas the primitive ints compare by value and == is true.

Finally, Objects.equals() safely handles a null operand where calling actual.equals(...) would throw a NullPointerException.

Go beyond the one-line answer: state that Object's default equals() is reference-based and that String overrides it, then mention the equals()/hashCode() contract — that pairing is the classic follow-up. Expect probes like "why does == sometimes work for strings?" (string pool) and "what happens with Integer values outside -128 to 127?" (integer cache).

A classic trap is comparing WebDriver text output with ==, which fails even when the text matches because getText() returns a new String object — say you always use equals() or assertEquals() in your framework.