RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
Java questions
MediumJava#217 min readJul 11, 2026

Why is String immutable?

java
practice
string
learning
Practice modeTest yourself instead of reading straight through

Interviewers love this one because a tiny design choice in String quietly powers security, caching, and thread safety everywhere in Java.

Question: Why is String immutable?

Answer: String is immutable because once a String object is created, its text cannot change. Any operation that looks like a change, such as concatenation or replacement, creates a new String instead. This makes Strings safe to share, safe to use as map keys, and easy for the JVM to cache.

Interview-Ready Answer: I’d say String is immutable so Java can safely share text across the runtime without worrying that some code will change it later. That gives us thread safety, stable hash codes for hash-based collections, and efficient pooling of repeated literals. When I need frequent edits, I use StringBuilder instead of trying to mutate a String.

🧠 Memory Map
Memory map — visual summary of this topic

What immutability really means

A String is immutable when its visible text cannot be changed after construction. In plain words: you can point a variable at a different String, but you cannot edit the characters inside an existing String object.

How it works under the hood

  1. Java creates the String object with private storage that user code cannot reach directly. In modern Java, the internal storage is a private final byte[] plus a small encoding flag; older Java versions used char[].
  2. The class is final, so nobody can subclass it and sneak in mutating behavior. That helps the JVM trust that String behaves consistently.
  3. The constructors copy incoming data. If you build a String from a char[], later changes to that array do not affect the String.
  4. There are no public setter methods like setCharAt or append on String. Methods such as concat, replace, or substring return a new String value.
  5. Because the content never changes, the JVM can safely cache the hash code. That matters because Strings are often used as keys in HashMap and HashSet.
  6. The JVM can also pool identical literals and interned strings. A String literal like "java" can be shared instead of copied many times, which saves memory and speeds up comparisons.

Why Java designed it this way

  • Security: Strings are used for file paths, class names, URLs, SQL text, and configuration values. If they were mutable, code could validate a value and then have it change later, which is a classic bug and security risk.
  • Thread safety: Immutable objects are naturally safe to share between threads because no thread can change the shared state. No lock is needed just to read a String.
  • Performance: Stable hash codes make map lookups fast, and pooling reduces duplicate objects. On modern JVMs, compact strings also help memory usage: Latin-1 text can use 1 byte per character, while non-Latin-1 text uses 2 bytes per character.

String vs mutable alternatives

TypeMutable?Thread-safe?Best use
StringNoYesRead-only text
StringBuilderYesNoFast single-threaded building
StringBufferYesYesLegacy synchronized building

Performance and edge cases

  • Creating a changed String is usually O(n) because Java must copy characters into a new object.
  • Repeated + in a loop can become expensive, often close to O(n^2) overall, because many temporary Strings are created.
  • StringBuilder.append is amortized O(1) per append, and the final toString() is O(n). That is why builders are preferred for heavy concatenation.
  • Modern Java no longer relies on the old substring-sharing trick. Today, substring typically copies the needed range, so you do not keep a giant backing array alive by accident like in very old JVMs.
  • intern() does not make String mutable; it only asks the JVM to return a shared pooled instance for equal text.

Memory hook: think of a String like a sealed envelope. You can write a new envelope with updated text, but you cannot erase and rewrite the one already sent.

Real-world story

Imagine a checkout service for an e-commerce app. It uses order IDs, coupon codes, and request IDs as keys in caches, logs, and audit trails. Because Strings are immutable, one request can validate an ID and another thread can safely log the exact same value without fear that some later code will quietly change it.

What goes wrong when people misunderstand this: a team uses a mutable text holder for cache keys and then keeps appending trace data to it. Suddenly the cache starts missing entries, logs stop matching orders, and the payment service begins hammering the database for the same lookups. In production, this shows up as rising latency, duplicate processing, and confusing log lines like "order not found" even though the order was just created.

With String, that class of bug is much harder to create because the key you inserted into the cache will always stay the same.

Java
import java.util.HashMap;
import java.util.Map;

public class StringImmutabilityDemo {
    public static void main(String[] args) {
        // The String constructor copies the source characters.
        // Changing the original array later does not change the String.
        char[] letters = {'J', 'a', 'v', 'a'};
        String text = new String(letters);
        letters[0] = 'X';
        System.out.println("String after source array change: " + text);

        // A String is safe to use as a map key because its content never changes.
        Map<String, Integer> cache = new HashMap<>();
        cache.put(text, 1);

        // Equal text finds the same key.
        System.out.println("Lookup with equal text: " + cache.get("Java"));

        // Concatenation does not mutate the old String.
        // It creates a brand-new String, so the variable now points somewhere else.
        text = text + "!";
        System.out.println("Variable after concat: " + text);

        // This lookup fails because the key text is now different.
        System.out.println("Lookup with changed text: " + cache.get(text));
        System.out.println("Original key still works: " + cache.get("Java"));

        // StringBuilder is the mutable alternative when you need repeated edits.
        StringBuilder builder = new StringBuilder("Java");
        builder.append("!");
        builder.append(" Rocks");
        System.out.println("StringBuilder result: " + builder);
    }
}

Follow-up & Tricky Questions:

  • Why does immutability help HashMap? Because the hash code of a String stays stable for its whole life, so the key can be found in the same bucket later. If the text could change, the key might move logically without the map knowing.
  • What is the difference between String and StringBuilder? String cannot change after creation, while StringBuilder is mutable and optimized for repeated appends. Use StringBuilder when you are building text in a loop or assembling a large message.
  • Why is StringBuffer different from StringBuilder? StringBuffer is also mutable, but its methods are synchronized, meaning it adds locking for thread safety. That makes it older and usually slower than StringBuilder for single-threaded code.
  • How does String pooling work? The JVM keeps a shared pool of equal text values so literals and interned strings can be reused. Immutability is what makes that safe, because nobody can later change the shared object.
  • Does substring still share the original array? In modern Java, no: substring copies the relevant characters. Older JVMs once shared arrays, which could accidentally keep a large buffer alive for too long.
  • Is String immutable because it is final? Not only that. final helps, but immutability mainly comes from private internal storage, no mutator methods, and defensive copying of input data.
  • Can I rely on intern() for performance everywhere? No. It can help when you have many repeated identical strings, but overusing it can add complexity and memory pressure. Use it only when you have a clear reason.
  • Tricky: if s = s + "x", did String mutate? No. The old String still exists unchanged; the variable s is just reassigned to a new object.
  • Tricky: are all equal String literals the same object? Often yes for pooled literals, but do not depend on object identity unless you intentionally use intern(). In general, compare Strings with equals(), not ==.
  • Tricky: does immutable mean automatically fast? Not always. Copying text takes time and memory, so repeated changes can be slower than a mutable builder. Immutability trades edit speed for safety and sharing.

Common Mistakes:

  • Thinking String can be edited in place. Correction: every apparent change returns a new String; the old one stays unchanged.
  • Using + in big loops. Correction: use StringBuilder for repeated concatenation, then call toString() once at the end.
  • Comparing Strings with ==. Correction: == checks object identity, not text equality; use equals().
  • Believing immutability means zero cost. Correction: creating new Strings copies data, so there is still allocation and CPU work.

Memory Hook: A String is a sealed envelope: you can write a new one, but you cannot rewrite the one already sealed.

Cheat Sheet:

  • String content cannot change after creation.
  • Operations like concat and replace create new objects.
  • Immutability makes Strings thread-safe to share.
  • Stable content means stable hash codes for map keys.
  • JVM can pool and reuse identical literals safely.
  • Use StringBuilder for lots of edits; use String for read-only text.

Practice Tasks:

  • Write a small program that shows a String does not change when the source char array changes.
  • Compare a loop that builds 10,000 pieces with + versus StringBuilder.
  • Put a String into a HashMap, reassign the variable, and observe why the original key still works.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

import java.util.HashMap; import java.util.Map; public class StringImmutabilityDemo { public static void main(String[] args) { // The String constructor copies the source characters. // Changing the original array later does not change the String. char[] letters = {'J', 'a', 'v', 'a'}; String text = new String(letters); letters[0] = 'X'; System.out.println("String after source array change: " + text); // A String is safe to use as a map key because its content never changes. Map<String, Integer> cache = new HashMap<>(); cache.put(text, 1); // Equal text finds the same key. System.out.println("Lookup with equal text: " + cache.get("Java")); // Concatenation does not mutate the old String. // It creates a brand-new String, so the variable now points somewhere else. text = text + "!"; System.out.println("Variable after concat: " + text); // This lookup fails because the key text is now different. System.out.println("Lookup with changed text: " + cache.get(text)); System.out.println("Original key still works: " + cache.get("Java")); // StringBuilder is the mutable alternative when you need repeated edits. StringBuilder builder = new StringBuilder("Java"); builder.append("!"); builder.append(" Rocks"); System.out.println("StringBuilder result: " + builder); } }