In Java, what is the difference between using == and equals() to compare two String objects?
answer
- == compares references (identity)
- equals() compares characters (content)
- String pool makes == look right for literals
- Use equals() for text, == for primitives
- Objects.equals() for null-safety
basics
~10 s== checks whether two String variables point to the same object in memory. equals() checks whether the two strings contain the same characters. To compare text, always use equals().
solid answer
~40 sString is an object, so a String variable holds a reference (a memory address), not the characters themselves. The == operator compares those references: it is true only when both variables point to the exact same object. equals(), as overridden in String, compares content character by character, returning true when the sequences of characters are identical. Because you almost always care about the text and not object identity, you should use equals() (or equalsIgnoreCase() for case-insensitive checks). A common pitfall: == can accidentally return true for string literals because of the string pool, then fail once a string is built at runtime, producing bugs that pass in simple tests but break in production. The safe rule is: == for primitives and identity, equals() for object content, including Strings.
code
java · 12 linesString a = "hi";
String b = "hi";
String c = new String("hi");
System.out.println(a == b); // true (both pooled literal)
System.out.println(a == c); // false (c is a new object)
System.out.println(a.equals(c)); // true (same characters)
// Null-safe content comparison:
String input = null;
System.out.println("hi".equals(input)); // false, no exception
System.out.println(java.util.Objects.equals(a, input)); // false, no exceptiongo deeper
Knows the rule: use equals() for text, == for the same object, and can state that == compares references while equals() compares characters.
Explains the string pool and can predict == results for literals vs new String(...) vs runtime concatenation, and uses Objects.equals/null-safe ordering.
Connects this to the general reference-vs-value model for all objects, the equals/hashCode contract, and the interning trade-offs; writes null-safe, locale-aware comparisons by habit.
Frames it as part of API/identity design, sets team conventions (always equals() for content, Objects.equals for nullable), and reasons about pooling/interning memory implications at scale and in security-sensitive comparisons.
## First, what a String actually is In Java there are two kinds of types. **Primitives** (`int`, `boolean`, `char`, `double`, etc.) hold a raw value directly in the variable. **Reference types** (everything else, including `String`) hold a *reference* — think of it as the address of an object that lives elsewhere in memory (on the heap). The variable is a label pointing at the object; it is not the object itself. So when you write `String a = "hi";`, the variable `a` does not contain the letters h and i. It contains a pointer to a `String` object that contains those letters. ## What `==` does The `==` operator always compares the *contents of the variables*. For primitives that is the value itself (`5 == 5` is true). For reference types, the content of the variable is the reference, so `==` asks: **"do these two variables point to the exact same object?"** This is called *reference equality* or *identity*. It does NOT look inside the objects. ## What `equals()` does `equals()` is a method defined on `Object` (the root class of everything). The default `Object.equals()` just does `this == other` — identity again. But `String` *overrides* `equals()` to compare content: it checks that the other object is also a String, has the same length, and has the same character at every position. So `String.equals()` returns true exactly when the two strings represent the same text. This is *content/value equality*. ```java String a = new String("hi"); String b = new String("hi"); System.out.println(a == b); // false — two different objects System.out.println(a.equals(b)); // true — same characters ``` ## Why beginners get confused: the string pool Java keeps a special cache called the **string pool** (string intern pool). When you write a *string literal* like `"hi"` in your source code, the compiler/runtime reuses one shared object for all identical literals. So: ```java String a = "hi"; String b = "hi"; System.out.println(a == b); // true — both refer to the SAME pooled object ``` Here `==` returns `true`, which fools people into thinking `==` compares text. It does not — it just happens that both literals point to the one pooled instance. The moment a string is produced at runtime (via `new String(...)`, concatenation of variables, `StringBuilder`, reading input, substring, etc.) it is a *different* object, and `==` becomes `false` even though the text is identical: ```java String a = "hi"; String b = new String("hi"); System.out.println(a == b); // false — b is a fresh object System.out.println(a.equals(b)); // true ``` This is the classic production bug: code compares strings with `==`, works during quick literal-based testing, then fails on real runtime-built input. ## The rule to remember - Comparing **text** → use `equals()` (or `equalsIgnoreCase()` to ignore case). - Comparing **identity** ("is it literally the same object?") → use `==` (rare for strings). - For primitives → use `==` (there is no `equals` for primitives). ## Null-safety bonus Calling `equals()` on a possibly-null reference throws `NullPointerException`. To be safe, either call it on a known-non-null value (`"yes".equals(input)`) or use `java.util.Objects.equals(a, b)`, which handles nulls. `==` never throws, but it does the wrong comparison for text.
- Why does == sometimes return true for two strings with the same text?Because string literals are interned in the string pool, so identical literals point to one shared object. == is true purely by coincidence of identity, not because it compares characters.
- How do you compare two strings ignoring case?Use equalsIgnoreCase(), e.g. a.equalsIgnoreCase(b). Avoid lowercasing both with toLowerCase() in locale-sensitive code unless you pass a Locale, since some locales (e.g. Turkish) transform letters unexpectedly.
Two people can have identical printed copies of the same letter (equal content) without it being the same physical sheet of paper (same reference). == asks 'same sheet of paper?'; equals() asks 'same words?'.
saying these in an interview costs you the question
- Claiming == compares string content
- Saying equals() compares references
- Believing == always works because it 'worked in my test' (only true for literals)
- Calling equals() on a possibly-null variable without guarding against NPE