String is an immutable object, not a primitive. Literals are interned in the string pool, so == sometimes “works” — and that is exactly the trap.
Creating strings
| Form | Where it lives | Notes |
|---|---|---|
String a = "hi"; | String pool (interned) | Identical literals in the whole JVM share one object |
String b = new String("hi"); | A new heap object | Always a distinct object — almost never what you want |
"h" + "i" | Pool | Constant expression — folded to "hi" by the compiler |
s1 + s2 (non-final variables) | New heap object | Built at runtime (via StringConcatFactory since Java 9) |
b.intern() | Pool | Returns the pooled copy (adds it if missing) |
== vs equals()
public class Main {
public static void main(String[] args) {
String a = "java";
String b = "java";
String c = new String("java");
String d = "ja" + "va"; // compile-time constant → pooled
String part = "ja";
String e = part + "va"; // runtime concatenation → new object
System.out.println(a == b); // same pooled object
System.out.println(a == c); // different objects
System.out.println(a.equals(c)); // same characters
System.out.println(a == d);
System.out.println(a == e);
System.out.println(a == e.intern());
}
}true
false
true
true
false
trueImmutability in action
public class Main {
public static void main(String[] args) {
String s = "hello";
s.toUpperCase(); // result discarded — s is unchanged
System.out.println(s);
s = s.toUpperCase(); // rebind the variable to the new object
System.out.println(s);
String t = s;
s = s + "!"; // creates a new String; t still points at the old one
System.out.println(t + " " + s);
}
}hello
HELLO
HELLO HELLO!Why is String immutable?
Concatenation in loops
Each += on a String allocates a new object and copies all characters so far — O(n²) for a loop of n appends. Use StringBuilder (next topics) or String.join / Collectors.joining.
public class Main {
public static void main(String[] args) {
String slow = "";
for (int i = 0; i < 5; i++) slow += i; // 5 new String objects
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) sb.append(i); // one growing buffer
System.out.println(slow + " " + sb);
System.out.println(String.join("-", "a", "b", "c"));
}
}01234 01234
a-b-cHow many objects does new String("abc") create?
Where is the string pool located?
Why is char[] preferred over String for passwords?