原文:Why String is immutable in Java ?
String是Java中的一个不可变类。所谓不可变,简单来说就是其对象不能被修改。实例中的所有信息在初始化的时候就已经具备,并且不能被修改。不可变类有很多优点。这篇文章简要说明了为什么String被设计为不可变类。关于其好的回答应该建立在对内存模型、同步和数据结构等的理解之上。
1. 字符串池的需求
字符串池是一个位于方法区的特殊区域。当一个字符串被创建的时候,如果该字符串已经存在于字符串池中,那么直接返回该字符串的引用,而不是创建一个新的字符串。
下边的代码将只会创建一个字符串对象:1
2String s1 = "abcd";
String s2 = "abcd";
s1和s2都指向同一个字符串对象。
如果String不是不可变的,那么修改s1的字符串对象同样也会导致s2的内容发生变化。
2. 缓存Hashcode
字符串的hashcode在Java中经常被用到。例如,在一个HashMap中。其不可变性保证了hashcode(哈希值)总是保持不变,从而不用担心因hashcode变化导致的缓存问题。那就意味着,不用每次在其使用的时候计算其hashcode,从而更加高效。
在String类中,有如下代码:1
private int hash; //用来缓存hash code
3. 简化其他对象的使用
为了理解这一点,请看下边的代码:1
2
3
4
5
6HashSet<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的设计(set包含不重复的元素)。当然这个例子是有问题的,在String类中是不存在value这个属性的。(ps:个人觉得应该是没有可以直接访问的value,毕竟String中value数组是可以通过反射访问的,不知道,不知道这个老外是怎么个意思)
4.安全性
字符串在许多的java类中都用作参数,例如网络连接,打开文件等等。如果字符串是可变的,一个连接或文件就会被修改从而导致严重的错误。可变的字符串也会导致在使用反射时导致严重的问题,因为参数是字符串形式的。
举例如下:1
2
3
4
5
6
7boolean connect(String s) {
if (!isSecure(s)) {
throw new SecurityException();
}
// 如果s内的值被修改,则会导致出现问题
doSomethind(s);
}
(虽然略牵强,但是也有一定道理)
5. 不可变的对象本身就是线程安全的
不可变的对象,可以在多个线程间自由共享。从而免除了进行同步的麻烦。
总之, String被设计为不可变的类,是出于性能和安全性的考虑,这也是其他所有不可变类应用的初衷。