3.1 String Immutability & the String Constant Pool
What is a String in Java?
A String is a sequence of characters.
String name = "Sarwvidya";
// String stores multiple characters together.
// Internally, modern Java represents String data using a byte[]/compact representation
// when possible, but conceptually we can think of it as a sequence of characters.
Unlike C/C++, Java does not have a separate primitive string type.
String is a class in Java:
String name = "Java";
System.out.println(name.length()); // 4
So:
String
↓
Java class
↓
java.lang.String
You don't need to import it because java.lang is automatically available.
Two ways to create a String
Method 1: String literal
String s1 = "Java";
This is the most commonly used way.
Java uses a special memory area called the String Pool for string literals.
Method 2: Using new
String s2 = new String("Java");
This explicitly creates a new String object.
Important
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s3)); // true
Why?
s1 ───────┐
↓
"Java" ← String Pool
↑
s2 ───────┘
s3 ──→ separate String object
== compares references.
equals() compares content.
What is String Pool?
The String Constant Pool is a special area associated with the JVM's heap where Java maintains canonical String literals.
For example:
String a = "Hello";
String b = "Hello";
Java doesn't need two identical literal objects.
Conceptually:
a ─────┐
↓
"Hello"
↑
b ─────┘
So:
System.out.println(a == b);
prints:
true
This saves memory.
Therefore,
String Pool is a special area in the heap where Java stores and reuses String literals. If the same literal already exists, Java can reuse the existing object instead of creating another one.
Why is String immutable?
Immutable means: Once a String object is created, its value cannot be changed.
Example:
String s = "Java";
s.concat(" Developer");
System.out.println(s); // Output = Java
Many beginners expect output to be:
Java Developer
But output is:
Java
Because concat() creates a new String.
String s = "Java";
s = s.concat(" Developer");
System.out.println(s); // Java Developer
Now the reference s points to the new String.
Why is String immutable?
1. String Pool
Because Strings are reused through the String Pool, changing one String could affect other references.
For example:
String a = "Java";
String b = "Java";
If a could modify "Java" into "Python", then b could unexpectedly see "Python".
Immutability prevents this.
2. Security
Strings are commonly used for sensitive or important values such as:
File paths
Database URLs
Class names
Network connections
Authentication-related values
If Strings could change after validation, it could create security problems.
3. Thread safety
Because a String cannot change after creation, multiple threads can safely read the same String without synchronization for the String's own state.
4. HashMap / HashSet
Strings are frequently used as keys.
Map<String, Integer> map = new HashMap<>();
map.put("Java", 100);
If the String's content could change after it was used as a key, its hash code could change and the object could become difficult to locate in the map.
5. == vs equals()
== - Checks whether two references point to the same object.
equals() - Checks whether two Strings have the same content.
String a = new String("Java");
String b = new String("Java");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Because:
a ──→ Object 1: "Java"
b ──→ Object 2: "Java"
Different objects, same content.
What happens with +?
Consider:
String s = "Java";
s = s + " Developer";
Because String is immutable, Java creates a new String.
Conceptually:
"Java"
+
" Developer"
↓
"Java Developer"
The old "Java" object isn't modified.
For a small number of concatenations, this is fine. But repeatedly doing this can create unnecessary temporary Strings.
Example of String Constant Pool Memory Model
String s1 = "Java"; // Allocated in String Constant Pool
String s2 = "Java"; // Reuses the identical pool reference!
String s3 = new String("Java"); // Creates a separate Object in general Heap!
JVM Heap Space
┌───────────────────────────────────────────────────────────┐
│ String Constant Pool (SCP) │
│ ┌─────────────────────────────────┐ │
│ │ "Java" (Address: @0x100) │◄─── s1 & s2 │
│ └─────────────────────────────────┘ │
│ │
│ General Heap │
│ ┌─────────────────────────────────┐ │
│ │ new String instance (@0x200) │◄─── s3 │
│ │ (internal char/byte[] -> @0x100)│ │
│ └───────────────────────────────── ┘ │
└───────────────────────────────────────────────────────────┘
Resulting checks:
System.out.println(s1 == s2); // true (Same pool address)
System.out.println(s1 == s3); // false (Different heap address)
System.out.println(s1.equals(s3)); // true (Identical content)