牛骨文教育服务平台(让学习变的简单)

在Java中字符串(String)是一个不可改变的类。一个不可改变的类只是一个对象实例不可修改的简单类。当创建一个对象实例时,对象实例的所有信息都被初始化,并且信息不能被修改。对于不可改变的类来说还有很多优势。上一篇文章很好说明了为什么字符串被设计成不可改变的。只有你很好的掌握了内存,同步,数据结构等知识后,你才能很好的回答这个问题。

1.字符串常量池的需求

字符串常量区是方法区(Method Area)中一块特殊的存储区域。当一个字符串被创建,如果该字符串已经存在字符串常量区时,相应的返回存在字符串的引用,而不是去新创建一个新的对象返回它的引用。

下面的代码中只会在堆中创建一个字符串对象。

String string1 = "abcd";
String string2 = "abcd";

下面的图能很好的说明:

如果字符串是可以改变的,改动一个字符串的引用将会导致另一个引用出现错误值。

2.缓存HashCode(哈希码)

在Java中一个字符串的哈希码是经常被使用的,例如在hashMap中。不可改变性确保了哈希码总是会保持不变,这样我们就不必担心发生任何变化。换一句话说,我们没有必要每次使用字符串时都要计算哈希码(因为不可改变性确保哈希码保持不变),这是一种更有效率的方式。

在String类中,都会有下列代码:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence{
    /** Cache the hash code for the string */
    private int hash; // Default to 0
}

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)的设计(集中不包含重复的元素)。这个例子为简单考虑,在真实String类中没有value属性。

4.安全

String在很多Java类中广泛使用作为参数,例如,网络连接,打开文件等等。如果字符串是可改变的,那么网络连接或者文件都可能会被改变,将导致严重的安全威胁。方法还以为是连接到一台机器上,但实际上却没有。可变字符串可能会导致在反射中出现问题,因为这些参数都是字符串。

boolean connect(string s){
    if (!isSecure(s)) { 
       throw new SecurityException(); 
    }
    //如果在这之前s通过其他引用进行改变,这可能会出现问题
    causeProblem(s);
}

5.不可变对象是线程安全的

因为不可变对象是不可改变的,那么它们可以在多个线程之间自由的共享。这就取消了进行同步的需求。

总之,字符串被设计为不可变是为了效率和安全性考虑。这也就是一般情况下优先选择不可变对象的原因。

原文:Why String is immutable in Java ?