本文是对《Why String is immutable in Java》的翻译
以下是原文地址:https://www.programcreek.com/2013/04/why-string-is-immutable-in-java/
在Java中,String是不可变的。不可变类就是其实例对象无法被修改的类。实例中的所有信息在创建实例的时候初始化,不可修改。不可变类有很多的优点。本文总结了为什么String被设计成不可变的。这篇文章从内存、同步和数据结构的角度阐述了不变性的概念。
1. String Pool 的需要
String Pool(String intern pool) 是Method Area中的一块特殊存储区。当创建字符串时,如果该字符串已经存在于池中,则将返回该字符串的引用,而不是创建新对象。
下面的代码会在堆中只创建一个String对象。
String string1 = "abcd";
String string2 = "abcd";
System.out.println(string1 == string2) //true
如果String是可变的,使用一个引用更改字符串将导致其他引用的值错误
2. 缓存Hashcode
String的哈希值经常会被用到,例如在HashMap或HashSet中。不可变的特性保证了哈希值也是不可变的,这样它就可以被缓存而不用担心更改。这意味着,不需要在每次使用哈希值的时候都去计算,这样更有效率。
在String类中,有以下的代码:
private int hash; //该变量用来缓存哈希值
3. 方便其他对象的使用
具体来看以下代码:
HashSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));
for(String a: set)
a.value = "a";
在这个例子中,如果String是可变的,它的值可以改变,这将违反set的设计原则(set包含不可重复的元素)。当然,上面的例子只是为了演示的目的,在真正的String类中没有value字段。
4. 安全性
String被广泛用作许多Java类的参数,例如,网络连接、打开文件等等。如果String是可变的,那么一个连接或文件可能被更改,从而导致严重的安全威胁。该方法认为它连接到一台机器,但不是。可变String也可能导致反射中的安全问题,因为参数是String。
以下是示例代码:
boolean connect(String s){
if(!isSecure(s)){
throw new SecurityException();
}
// 如果s在此之前使用其他引用更改,则会导致问题。
causeProblem(s);
}
5. 不可变对象天生就是线程安全的
由于不可变对象不能被改变,所以它们可以在多个线程之间自由的共享。这消除了确保一致性的需求。
总之,出于效率和安全性的考虑,String被设计为不可变的。这也是为什么不可变类在许多情况下通常是首选的原因。