skip to content

In Java, what is the difference between == and the equals() method when comparing two object references?

level: juniorimportance: must knowfreq 90%

answer

  1. == = identity (same heap object); equals() = value
  2. Object.equals default IS ==
  3. String/Integer/collections override equals()
  4. new String("a") == new String("a") is false, equals true
  5. primitives: == compares values, no equals()

basics

~10 s

== checks if two references point to the exact same object in memory (identity). equals() checks whether two objects are logically equal in value. They can disagree: two different objects can hold equal data.

solid answer

~40 s

For object references, == compares identity: it returns true only when both variables point to the very same object on the heap. equals() compares logical equality and is meant to answer "do these represent the same value?". The default Object.equals() just does ==, so unless a class overrides equals(), the two are identical. Value-based classes like String, Integer, and the collection classes override equals() so distinct objects with the same contents compare equal. Classic gotcha: new String("a") == new String("a") is false (two objects), but .equals() is true. For primitives (int, double, etc.) there are no references, so == compares the actual values and equals() doesn't apply. Rule of thumb: use == for identity and primitives, use equals() for value comparison of objects.

code

java · 10 lines
java
String a = new String("hi");
String b = new String("hi");
String c = a;

System.out.println(a == b);       // false  (different objects)
System.out.println(a == c);       // true   (same object)
System.out.println(a.equals(b));  // true   (same value)

int x = 5, y = 5;
System.out.println(x == y);       // true   (primitive value compare)

go deeper

for a junior

States the core distinction: == is same object, equals() is same value; knows to use equals() for Strings.

for a middle

Knows the default Object.equals() is identity, that value classes override it, and explains the new String gotcha; mentions Objects.equals for null safety.

for a senior

Connects to the equals/hashCode contract, string interning and the Integer cache as reasons == surprises, and when identity comparison is actually the right tool.

for a principal

Frames identity vs equality as a domain-modeling choice (entities have identity, value objects compare by state), and discusses how == leaks identity semantics into APIs (e.g. enum == vs equals, sentinel singletons).

## The two kinds of "same" When you ask whether two things are "the same", you can mean two different things: 1. **Identity** — "are these literally the *same* object?" (the same box in memory). 2. **Equality** — "do these two (possibly different) objects *represent the same value*?" Java gives you a separate tool for each. ## References vs objects (the foundation) In Java, every non-primitive variable holds a **reference** — essentially a pointer to an object that lives on the **heap** (the region of memory where objects are allocated). The variable is *not* the object; it's an address-like handle to it. ```java String a = new String("hi"); // object #1 on the heap; a points to it String b = new String("hi"); // object #2 on the heap; b points to it String c = a; // c points to the SAME object as a (#1) ``` ## `==` compares references (identity) For object types, `==` asks: *do these two variables hold the same reference?* — i.e. point to the same heap object. ```java a == b // false: different objects (#1 vs #2) a == c // true: same object (#1) ``` This is called **reference identity**. ## `equals()` compares value (logical equality) `equals(Object)` is a method declared on `java.lang.Object`. Its job is to answer *do these represent the same value?* The **default** implementation in `Object` is literally: ```java public boolean equals(Object o) { return this == o; } ``` So for a class that does **not** override `equals()`, `equals()` and `==` behave identically — both test identity. Many standard classes **override** `equals()` to compare contents instead. `String`, the wrapper types (`Integer`, `Long`, `Double`…), and the collection classes (`ArrayList`, `HashMap`…) all do this: ```java a.equals(b) // true: same characters "hi", even though different objects ``` ## Primitives are different Primitive types (`int`, `long`, `double`, `boolean`, `char`…) are **not** objects and hold no reference — the variable holds the value directly. So for primitives, `==` compares the actual values, and `equals()` doesn't apply (you can't call a method on a primitive). ```java int x = 5, y = 5; x == y; // true: compares the values 5 and 5 ``` ## The canonical gotcha ```java String s1 = new String("a"); String s2 = new String("a"); s1 == s2; // false (two distinct objects) s1.equals(s2); // true (same value) ``` Because `String` overrides `equals()`, comparing string *contents* must use `.equals()`. Using `==` on strings is a frequent bug. ## Practical rule - Comparing **object values** → use `equals()` (or `Objects.equals(x, y)` to be null-safe). - Checking whether two variables are the **same object** (rare, e.g. cache identity) → use `==`. - Comparing **primitives** → use `==`. The two only coincide when a class hasn't overridden `equals()`.

  • Why does new String("a") == new String("a") return false but "a" == "a" return true?
    new String(...) always creates a fresh object, so two news are distinct references (== false). String literals are interned into a shared pool, so "a" == "a" points to the same pooled object (== true). .equals() returns true in both cases.
  • What does the default Object.equals() do?
    It returns this == o — pure reference identity. So unless a class overrides equals(), equals() and == behave identically.

saying these in an interview costs you the question

  • Claiming == always compares values for objects
  • Saying equals() compares memory addresses (it compares value, when overridden)
  • Forgetting that the DEFAULT equals() is just == (identity)
  • Using == to compare String contents
  • Thinking equals() applies to primitives

context