为什么在Java中String是不可变的?
在java中String是不一个不可变的类。一个不可变的类仅仅是它的实例不能被修改。当一个实例被创建的时候实例中的所有信息都被初始化并且不能被改变。不可变类有许多的优点。这篇文章总结了String为什么被设计成不可变的。一个好的回答基于对内存、同步和数据结构等的深入理解。
1. 字符串常量池的需要
字符串常量池在方法区中是一个特殊的存储区域。当一个string被创建并且已经在池中存在,返回的是对已经存在的string的引用,而不是创建一个新的对象并且返回该对象的引用。
下面的代码将只在堆(译者注:貌似是方法区)中创建一个string对象。
String string1= "abcd";
Stringstring2= "abcd";
如下所示:
如果一个字符串是可变的,改变该字符串的一个引用将会导致其他引用的值错误。
2. 缓存Hashcode
string的hashcode在Java中经常被用到。例如,在HashMap中。字符串的不变性保证了hashcode的唯一性,因此它可以被兑现而不用担心改变。这意味着,不用在每次用到的时候去计算hashcode。这更加的高效。
在String类中有如下代码:
private int hash;//被用作缓存hash code
3. 促进其它对象的使用
为了使其具体化,考虑下面的程序:
HashSet<String> set= new HashSet<String>();
set.add(newString("a"));
set.add(newString("b"));
set.add(newString("c"));
for(String a: set)
a.value= "a";
在这个例子中,如果String是可变的,它的值能被改变,这将违背set的设计(set 包含不可重复的元素)。这个例子是简单起见而设计的,在真正的String类中没有value这个字段。
4. 安全
String在许多java类中被用作一个参数,例如网络连接、打开文件等等。如果String是可变的,一个连接或者文件将会被改变并且导致严重的安全威胁。这个方法认为它在连接一台机器,但却不是。当参数是strings时,可变的strings也将会在映射中导致安全问题。
下面是代码示例:
boolean connect(string s){
if (!isSecure(s)){
throw new SecurityException();
}
//如果s在这之前通过使用其他引用而被改变,这里将会产生问题
causeProblem(s);
}
5. 不可变对象生来是线程安全的
因为不可变对象不能被改变,它们可以在多线程中随意被共享。这消除了做同步的需要。
总而言之,鉴于效率和安全,String被设计成不可变的。这也是为什么一般来说优先考虑不可变类的原因。
英文原文链接:Why String is immutable in Java?
< (小白一枚,请多指教) />