Hiprup

Why are strings immutable in Java?

Strings are immutable in Java: once a String object is created, its value can never change. Methods such as concat(), replace(), and toUpperCase() never modify the original — they return a new object. The class is declared final and its internal value array (a char[] in Java 8, a byte[] since Java 9) is private, final, and never exposed, with no setter methods.

This deliberate design decision enables the string pool, guarantees thread safety, and protects security-sensitive data.

  • String pool efficiency — identical literals (for example, repeated locator strings in a Selenium framework) share one pooled object; that sharing is only safe because no reference can change the shared value.

  • Security — strings hold URLs, file paths, usernames, and database connection details; if strings were mutable, a validated value could be swapped afterwards, so immutability closes that attack window.

  • Thread safety — immutable objects need no synchronization, so strings shared during TestNG parallel execution are automatically safe for every thread to read.

  • Hashcode cachingString computes its hash once on first use and reuses it, making strings fast, reliable keys in structures like Map<String, WebElement>.

  • Class loading — class names are passed as strings, and immutability guarantees the JVM loads exactly the class that was requested.

Key terms: immutability, string pool, interning, thread safety, hashcode caching, final, StringBuilder

public class StringImmutabilityDemo {
    public static void main(String[] args) {
        String url = "https://vibeprep.ai";
        String upper = url.toUpperCase();   // returns a NEW object

        System.out.println(url);            // Output: https://vibeprep.ai (unchanged)
        System.out.println(upper);          // Output: HTTPS://VIBEPREP.AI

        String a = "selenium";
        String b = "selenium";              // reuses the pooled object
        System.out.println(a == b);         // Output: true  (same object from string pool)

        String c = new String("selenium");  // forces a new object on the heap
        System.out.println(a == c);         // Output: false (different objects)
        System.out.println(a.equals(c));    // Output: true  (same content)
    }
}

The snippet proves immutability: toUpperCase() leaves the original url untouched and returns a brand-new String. It then shows the payoff, the string pool: two identical literals a and b are == because the JVM shares one pooled object, while new String("selenium") always creates a separate heap object even though its literal argument is pooled.

That is why content comparison must always use equals(), not ==, a distinction interviewers frequently probe.

Structure your answer around the four classic reasons: string pool, security, thread safety, and hashcode caching — naming all four signals real depth. Expect follow-ups on concatenating strings in a loop (use StringBuilder) and the difference between String, StringBuilder, and StringBuffer.

A classic mistake is claiming String is immutable because the class is final: final only prevents subclassing, while immutability really comes from the private final internal array that is never exposed and the absence of mutator methods.