Java Notes
Deep dive into String immutability in Java covering why strings are immutable, internal implementation, String Pool, security implications, performance impact, and how immutability affects programming.
What Does Immutable Mean?
Immutable means "cannot be changed after creation." When we say Strings are immutable in Java, we mean that once a String object is created, its internal character data can never be modified. Any operation that appears to change a String actually creates a brand new String object with the modified content, leaving the original untouched.
Analogy
Think of a String like a printed book. You cannot erase or change the words already printed on the pages. If you want a different version, you must print an entirely new book. The original book remains exactly as it was.
Demonstration
public class ImmutabilityProof {
public static void main(String[] args) {
String original = "Hello";
System.out.println("Before any operation:");
System.out.println("Value: " + original);
System.out.println("Identity: " + System.identityHashCode(original));
// Each operation creates a NEW object
String upper = original.toUpperCase();
String concat = original.concat(" World");
String replaced = original.replace('l', 'L');
System.out.println("\nAfter operations:");
System.out.println("original: " + original + " (identity: " + System.identityHashCode(original) + ")");
System.out.println("upper: " + upper + " (identity: " + System.identityHashCode(upper) + ")");
System.out.println("concat: " + concat + " (identity: " + System.identityHashCode(concat) + ")");
System.out.println("replaced: " + replaced + " (identity: " + System.identityHashCode(replaced) + ")");
System.out.println("\nOriginal unchanged? " + original.equals("Hello"));
}
}Before any operation: Value: Hello Identity: 1283928880 After operations: original: Hello (identity: 1283928880) upper: HELLO (identity: 295530567) concat: Hello World (identity: 738847520) replaced: HeLLo (identity: 1649659830) Original unchanged? true
Key Observation: The original variable still points to the same object (same identity hashcode) with the same value "Hello". All operations created new objects with different identities.
How is Immutability Implemented?
The String class achieves immutability through several design decisions:
1. The class is declared final
public final class String { ... }This prevents any class from extending String and potentially overriding methods to allow mutation.
2. The internal character storage is private final
// Java 8 and earlier:
private final char[] value;
// Java 9+ (compact strings):
private final byte[] value;private— no external class can access the array directlyfinal— the reference cannot be reassigned to a different array- Note:
finaldoesn't make the array contents immutable, but since it'sprivateand no method modifies it, the contents are never changed.
3. No mutator (setter) methods
The String class has no methods that modify the internal value array. Methods like toUpperCase(), replace(), concat() all create and return new String objects.
4. Defensive copying in constructors
When a String is created from a char array, the array is copied (not stored directly):
public String(char[] value) {
this.value = Arrays.copyOf(value, value.length); // Defensive copy!
}This prevents the caller from modifying the internal state through the original array reference.
Why Are Strings Immutable? (5 Reasons)
Reason 1: String Pool Optimization
The String Pool allows sharing of string literals. If strings were mutable, changing one literal would affect all variables referencing it:
public class PoolSafety {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello"; // Same object as s1 (pool sharing)
System.out.println("s1 == s2: " + (s1 == s2)); // true — same object
// IMAGINE if strings were mutable:
// s1.modify("Bye"); // Would ALSO change s2! Catastrophic!
// Because strings are immutable, pool sharing is SAFE
System.out.println("s1: " + s1); // Always "Hello"
System.out.println("s2: " + s2); // Always "Hello"
}
}s1 == s2: true s1: Hello s2: Hello
Reason 2: Security
Strings are used for sensitive data: database URLs, file paths, network connections, class names. If strings were mutable, malicious code could change these after validation:
public class SecurityDemo {
// Simulated connection method
static void connect(String url) {
// Step 1: Validate URL
if (url.startsWith("https://trusted-server.com")) {
System.out.println("URL validated: " + url);
// Step 2: Actually connect
// If url were mutable, it could be changed between
// validation and connection — a TOCTOU attack!
System.out.println("Connecting to: " + url);
}
}
public static void main(String[] args) {
String url = "https://trusted-server.com/api";
connect(url);
// Because String is immutable, url CANNOT change between
// validation check and actual connection
}
}URL validated: https://trusted-server.com/api Connecting to: https://trusted-server.com/api
Reason 3: Thread Safety
Immutable objects are inherently thread-safe. Multiple threads can share the same String without synchronization because no thread can modify it:
Thread 1 done. shared = Thread-Safe Data Thread 2 done. shared = Thread-Safe Data Final value: Thread-Safe Data
Reason 4: HashCode Caching
Since Strings are immutable, their hashCode is computed once and cached. This makes Strings excellent keys in HashMaps (which use hashCode extensively):
public class HashCodeCaching {
public static void main(String[] args) {
String key = "important_key";
// hashCode is computed once and cached
int hash1 = key.hashCode();
int hash2 = key.hashCode(); // Returns cached value — O(1)
System.out.println("First call: " + hash1);
System.out.println("Second call: " + hash2);
System.out.println("Same? " + (hash1 == hash2));
// This is why Strings are the most common HashMap key
java.util.HashMap<String, Integer> map = new java.util.HashMap<>();
map.put("Alice", 95);
map.put("Bob", 87);
System.out.println("Map: " + map);
}
}First call: -1833212042
Second call: -1833212042
Same? true
Map: {Bob=87, Alice=95}If strings were mutable, the hashCode could change after insertion into a HashMap, making the entry unretrievable!
Reason 5: Class Loading Safety
The Java class loading mechanism uses String class names to load classes. If these strings could be modified, you could trick the JVM into loading different (malicious) classes.
The Performance Impact
The Problem: Concatenation in Loops
Because each modification creates a new object, string concatenation in loops is extremely inefficient:
String concatenation: 1850 ms StringBuilder: 2 ms Speedup: 925x
Why is String + slow?
Each result += "a" does this:
- Creates a new StringBuilder
- Copies ALL existing characters from
result - Appends "a"
- Creates a new String from the StringBuilder
- The old
resultString becomes garbage
For n iterations: copies 1 + 2 + 3 + ... + n = n(n+1)/2 characters → O(n²)
Memory Waste Visualization
| Iteration 1: result = "" + "a" | "a" (old "" becomes garbage) |
| Iteration 2: result = "a" + "a" | "aa" (old "a" becomes garbage) |
| Iteration 3: result = "aa" + "a" | "aaa" (old "aa" becomes garbage) |
| Iteration n: copies n-1 chars + 1 new = n chars (old string of n-1 chars | garbage) |
| Total objects created | n |
| Total characters copied | 1+2+3+...+n = O(n²) |
Proving Immutability with Reflection (Advanced)
While strings are immutable through the public API, you can technically break immutability using Reflection (not recommended!):
Before: Hello After hack: Bello WARNING: This corrupts the String Pool!
Never do this! It breaks the immutability contract, corrupts the String Pool (ALL references to "Hello" would see "Bello"), and violates security guarantees.
Creating Your Own Immutable Class
Understanding String's design helps you create your own immutable classes:
Student marks: [85, 90, 78] Student marks: [85, 90, 78]
Common Misconceptions
Misconception 1: "I modified the string!"
String s = "Hello";
s = "World"; // This doesn't modify "Hello" — it reassigns the referenceThe variable s is a reference that can be reassigned to point to a different object. The String object "Hello" itself is unchanged and still exists in the pool.
Misconception 2: "concat() changes the string"
String s = "Hello";
s.concat(" World"); // Creates new String but DISCARDS it!
System.out.println(s); // Still "Hello"!
// Must assign:
s = s.concat(" World"); // Now s points to new "Hello World"Misconception 3: "final means immutable"
final String s = "Hello";
// s = "World"; // COMPILE ERROR — cannot reassign final variable
// But this is about the VARIABLE, not the object's content!
// The object was already immutable. final just means the reference can't change.Advantages and Disadvantages of Immutability
Advantages
| Advantage | Explanation |
|---|---|
| Thread-safe | No synchronization needed |
| String Pool possible | Sharing saves memory |
| Security | Cannot be modified after validation |
| HashCode caching | Computed once, reused forever |
| Predictable | No side effects from sharing |
| Safe as HashMap key | Hash never changes after insertion |
Disadvantages
| Disadvantage | Explanation |
|---|---|
| Memory waste | New object for every modification |
| Performance in loops | O(n²) concatenation without StringBuilder |
| GC pressure | Many temporary String objects |
| Cannot modify in place | Must create new objects always |
Common Mistakes
- Forgetting to assign the result of String methods:
s.trim()withouts = s.trim() - Using + in loops instead of StringBuilder — O(n²) performance
- Thinking final variable = immutable object — they are different concepts
- Not understanding reference reassignment vs object modification
- Using reflection to break immutability — corrupts String Pool
Best Practices
- Always assign results of String methods back to a variable
- Use StringBuilder for building strings in loops
- Leverage immutability — share strings freely between threads
- Use strings as Map keys — their immutability guarantees hash consistency
- Don't worry about String Pool management — JVM handles it
- Use .intern() only when you have many duplicate dynamic strings
- Prefer string literals over
new String()for pool benefits - Design your classes immutable when possible — follow String's pattern
Interview Questions
Q1: Why are Strings immutable in Java? Five reasons: String Pool sharing, security, thread safety, hashCode caching, and class loading safety.
Q2: Can you modify a String object? Not through the public API. Reflection can technically bypass this but should never be used.
Q3: What happens when you do s = s + "world"? A new String "helloworld" is created. The variable s is reassigned to point to it. The old "hello" is unchanged.
Q4: How does immutability help with HashMap? Immutable keys guarantee that hashCode never changes after insertion, so the entry can always be found in the correct bucket.
Q5: What is the String Pool? A special memory area (inside heap since Java 7) that stores unique string literals. Immutability enables safe sharing of these instances.
Q6: How to create your own immutable class? Make class final, fields private final, no setters, defensive copy in constructor and getters for mutable fields.
Q7: Why is String concatenation in loops slow? Each += creates a new String object, copying all existing characters. Total work: O(n²).
Q8: What does intern() do? Returns the String Pool reference for the string. If not in pool, adds it. Enables == comparison.
Q9: Is String a value type or reference type? Reference type (object on heap), but treated specially by Java (literals, + operator, Pool).
Q10: How many objects are created by String s = "a" + "b" + "c"? Just 1 — the compiler optimizes literal concatenation to "abc" at compile time.
Q11: Can two different String variables point to the same object? Yes — this is exactly what the String Pool does for identical literals.
Q12: What is the difference between String immutability and final variable? Immutability means the object's content cannot change. Final variable means the reference cannot be reassigned. A final variable can still point to a mutable object.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Immutable Strings in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, fundamentals, strings, immutable
Related Java Master Course Topics