Mastery
Mastery/Java/A. Object model, identity & memory
T1 · high-leverage
Compare with Python: Identity vs. equality, and reference caching

== vs .equals(), and the String constant pool

== on objects compares reference identity. .equals() compares logical equality (as defined by the class). String literals are special: the JVM interns them in a shared constant pool, so two identical literals ARE the same reference — but new String(...) deliberately creates a distinct heap object even if the contents match. .intern() looks a string up in (or adds it to) the pool.

java
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

System.out.println("s1 == s2 (both literals, pooled):      " + (s1 == s2));
System.out.println("s1 == s3 (s3 is `new String(...)`):    " + (s1 == s3));
System.out.println("s1.equals(s3):                         " + s1.equals(s3));
System.out.println("s1 == s3.intern():                     " + (s1 == s3.intern()));

Interview angle

One of the single most common Java interview questions, precisely because it's easy to get partially right — most candidates know "use .equals(), not ==" without understanding the mechanism, which is exactly what a good follow-up like "what about new String(\"x\")?" is designed to expose. A strong answer explains the constant pool, not just the rule.

In the industry

Static analysis flags this by default in essentially every serious Java codebase's CI (SpotBugs' ES_COMPARING_STRINGS_WITH_EQ, and equivalent built-in IDE inspections in IntelliJ and Eclipse). Any team without that lint gate has almost certainly shipped this bug at least once — it's rare enough to catch in manual review because it often works in casual testing (small literal strings get pooled) and only breaks on strings built at runtime.