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 overriddenequals()asks "same data?".String pool caveat — identical string literals share one pooled object, so
==can appear to work, butnew String("x")creates a separate object and breaks it; always useequals()for strings.equals()/hashCode() contract — objects equal by
equals()must return the same hash code, orHashMap<String, Integer>andHashSetlookups misbehave.Null safety — calling
equals()on anullreference throwsNullPointerException; preferObjects.equals(a, b)or"expected".equals(actual).Test-automation practice — TestNG's
Assert.assertEquals()relies onequals(); comparingdriver.getTitle()orgetText()results with==fails even when the text matches, because WebDriver returns a newStringobject.
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.