Difference Between == and equals() for String
String.equals() algorithm:
π’ Junior Level
== compares memory addresses (whether itβs the same object).
equals() compares content (whether the text inside is the same).
Example:
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); // true β same object in String Pool
System.out.println(s1 == s3); // false β s3 is a separate object
System.out.println(s1.equals(s3)); // true β text is the same
Rule: For strings always use equals(). The == operator β only for null checks.
π‘ Middle Level
How equals() works
String.equals() algorithm:
- First checks
==(fast path β if itβs the same object, immediatelytrue) - Checks that the object is a
String - Compares the
coderfield (same encoding?)
coder(Java 9+) β a flag indicating whether the string is stored as Latin1 (1 byte/char) or UTF-16 (2 bytes/char).
- Compares lengths
- Character-by-character comparison of
byte[]arrays
// Simplified
public boolean equals(Object o) {
if (this == o) return true; // Fast path
if (!(o instanceof String)) return false;
String other = (String) o;
if (this.value.length != other.value.length) return false;
return Arrays.equals(this.value, other.value);
}
Typical mistakes
-
Mistake:
s1.equals(s2)whens1can benullSolution:"constant".equals(variable)orObjects.equals(s1, s2) -
Mistake: Thinking
==works for identical literals always Solution: This only works for literals in the same class. External data β in heap.
Comparison
| Criterion | == | equals() |
| βββββ- | ββββββ | ββββββββββββββββββββββββ |
| What compares | References (identity) | Content (equality) |
| Speed | O(1) | O(1) for identical, O(n) for different objects with same content |
| For literals | Works | Works |
| For new String() | Doesnβt work | Works |
| null-safe | Yes (s == null) | No (s.equals() will throw NPE) |
π΄ Senior Level
Internal Implementation
Bytecode comparison:
// == β if_acmpeq (JVM instruction: compare references)
// equals() β invokevirtual java/lang/String.equals
OpenJDK implementation (Java 9+):
public boolean equals(Object anObject) {
if (this == anObject) return true;
if (anObject instanceof String anotherString) {
if (coder == anotherString.coder) {
return isLatin1()
? StringLatin1.equals(value, anotherString.value)
: StringUTF16.equals(value, anotherString.value);
}
}
return false;
}
// StringLatin1.equals β intrinsic
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) return false;
}
return true;
}
return false;
}
@HotSpotIntrinsicCandidate β JVM replaces Java code with optimized CPU instructions (SIMD vectorized comparison).
Architectural Trade-offs
Identity (==) vs Equality (equals()):
==β identity check of objects (reference equality)equals()β content equivalence check (logical equality)
equals() contract:
- Reflexivity:
x.equals(x)is alwaystrue - Symmetry:
x.equals(y)==y.equals(x) - Transitivity: if
x.equals(y)andy.equals(z), thenx.equals(z) - Consistency: repeated calls give the same result
- For any
x:x.equals(null)βfalse
Edge Cases
-
Contract with hashCode(): If
s1.equals(s2)βs1.hashCode() == s2.hashCode(). InStringthis is maintained β hash is computed from content. -
Coder mismatch: A
Stringwith Latin1 ("abc") and aStringwith UTF-16 ("abc"+ Cyrillic) βequals()returnsfalseat thecodercheck stage, even if characters look the same. -
String deduplication (G1 GC): Combines
byte[]arrays, butStringobjects remain different.==returnsfalse,equals()βtrue.
Performance
| Scenario | == | equals() |
| βββββββββββ | ββ | βββββββ |
| Identical objects | ~0.3ns | ~0.3ns (fast path) |
| Same content, different objects | ~0.3ns | ~2-5ns (SIMD) |
| Different content, same length | ~0.3ns | ~1-2ns (early exit) |
| Different lengths | ~0.3ns | ~0.5ns (length check) |
Production Experience
Scenario: Auth middleware β API key verification:
// BAD: == β can be bypassed if hacker guessed the address
if (apiKey == expectedKey) { grant(); }
// GOOD: equals()
if (expectedKey.equals(apiKey)) { grant(); }
// BETTER: constant-time comparison (protection from timing attacks)
if (MessageDigest.isEqual(expectedKey.getBytes(), apiKey.getBytes())) { grant(); }
// Note: getBytes() creates new arrays β this is an allocation.
// For high-load systems consider comparison at byte[] level directly.
Best Practices for Highload
equals()β default choice for content comparisonObjects.equals(a, b)β null-safe, delegates toa.equals(b)"CONSTANT".equals(variable)β null-safe without extra objects- For security-sensitive comparison: constant-time algorithms (protection from timing attacks)
==β only fornullchecks and guaranteed interned strings
π― Interview Cheat Sheet
Must know:
==compares references (memory addresses),equals()β string contentequals()has a fast path: first checks==(if same object β immediatelytrue)String.equals()checks coder, length, then character-by-character comparison==β O(1),equals()β O(n) where n β string lengthequals()may throw NPE if called onnullβ use"const".equals(var)orObjects.equals()- JVM optimizes
equals()via SIMD instructions for short strings - For security-sensitive comparison use constant-time comparison
Frequent follow-up questions:
- Can you use
==for strings? β Only for null checks (s == null) or guaranteed interned strings. In 99% of cases β no. - Why is
equals()faster than it seems? β Fast path==+ SIMD optimization + early exit on mismatch. - Whatβs faster:
==orequals()? β==is always O(1), butequals()for identical objects is also O(1) via fast path. equals()contract? β Reflexivity, symmetry, transitivity, consistency,x.equals(null) β false.
Red flags (DONβT say):
- β β
==compares string contentβ β compares only references - β β
equals()is always slowβ β fast path makes it O(1) for identical objects - β βYou can compare strings via
==if theyβre the sameβ β only works for literals in the same class - β β
equals()doesnβt work with nullβ β correctly returnsfalsefornullargument
Related topics:
- [[1. How String Pool Works]]
- [[2. Difference Between Creating String via Literal and via new]]
- [[9. Can You Use == to Compare Strings]]
- [[4. Why String is Immutable]]