Why is String Immutable and Final in Java?
The String class in Java is immutable (cannot be modified) and final (cannot be subclassed). This design choice was made for security, performance, and thread safety reasons.
1. Security
If String were mutable, it could be changed unintentionally or maliciously, leading to security vulnerabilities.
Example:
public class SecurityExample {
public static void main(String[] args) {
String password = "mySecret";
// If String were mutable, a malicious function could change its value!
authenticate(password);
System.out.println(password); // Still "mySecret", ensuring security
}
static void authenticate(String password) {
// If String were mutable, an attacker could modify `password`
}
}
🛑 Problem if String were mutable: A hacker could modify password while being processed.
✅ Solution: Since String is immutable, it remains unchanged, ensuring safe authentication.
Security Example: Preventing URL Tampering
String url = "https://secure-site.com/login";
connectToServer(url);
If url were mutable, a malicious program could change "secure-site.com" to "fake-site.com".
2. Memory Optimization (String Pool)
Since String is immutable, Java reuses strings efficiently using the String Pool.
Example:
String s1 = "Hello";
String s2 = "Hello"; // Same reference as s1
System.out.println(s1 == s2); // true
✅ Benefit: Java reuses existing string literals, reducing memory consumption.
If String were mutable, two references (s1 and s2) could point to the same object, leading to unexpected changes.
3. Thread Safety
Since String objects cannot be modified, they are inherently thread-safe.
Example:
class SharedResource {
static String message = "Hello";
}
public class ThreadSafetyExample {
public static void main(String[] args) {
new Thread(() -> System.out.println(SharedResource.message)).start();
new Thread(() -> System.out.println(SharedResource.message)).start();
}
}
✅ Benefit: No need for synchronization—multiple threads can safely share a String object.
If String were mutable, one thread could change it while another is reading, causing race conditions.
4. HashCode Caching for Performance
- Since
Stringis immutable, its hash code is computed only once and cached. - This improves performance when using
Stringin hash-based collections (HashMap,HashSet).
Example:
public class HashCodeExample {
public static void main(String[] args) {
String s = "Java";
System.out.println(s.hashCode()); // Computed once and cached
System.out.println(s.hashCode()); // Fast lookup
}
}
✅ Benefit: HashMap lookups are faster because the hash code does not change.
If String were mutable, the hash code could change, making it unusable in hash-based collections.
5. Preventing Unintended Changes
If String were mutable, a single modification could affect multiple references.
Example:
String s1 = "Java";
String s2 = s1; // s1 and s2 point to the same object
s1 = s1 + " Rocks!"; // Creates a new object, s2 remains unchanged
System.out.println(s1); // Java Rocks!
System.out.println(s2); // Java
✅ Benefit: Modifications create new objects, preventing accidental changes.
If String were mutable, modifying s1 would also modify s2, leading to unpredictable behavior.
6. final Prevents Subclassing
The final keyword prevents inheritance of the String class.
public final class String {
// Implementation
}
✅ Why?
- Prevents overriding methods that could break immutability.
- Protects security-sensitive operations (e.g., hashing, pooling).
If String were not final, malicious subclasses could modify its behavior.
Key Takeaways
| Reason | Benefit |
|---|---|
| Security | Prevents modification of sensitive data (e.g., passwords, URLs). |
| Memory Efficiency | Enables String Pooling (string reuse, less memory). |
| Thread Safety | No need for synchronization—safe for multithreading. |
| Performance Boost | Hash code is cached, making hash-based collections faster. |
| Predictability | Prevents unintended modifications when passing strings around. |
Prevent Subclassing (final) | Ensures immutability and prevents security risks. |
Conclusion
✅ Java String is immutable to ensure security, performance, and thread safety.
✅ Being final prevents modification through subclassing.
✅ This makes Java’s string handling highly efficient and reliable.