String在Java中是个不可更改的类。一个不可更改的类简单来说就是这个类的所有实例是不可以更改的。所有的实例信息在创建的时候被初始化而且信息是不可以更改的。不可更改的类有很多好处。
这篇文章总结了为什么String被设计成不可以改变的。一个好的回答需要深入理解内存、同步和数据结构等。
字符串池的需要
字符串池(字符串内部池) 是在方法区域的特殊区域。当一个string被创建如果这个string已经在内存里面存在了,那个存在的string的引用被返回,而不是创建个新的对象和返回它的引用。
下面的代码将在堆上创建一个string对象。
String string1 = "abcd"; String string2 = "abcd";
如果这个string是可以改变的,通过一个引用改变一个string将导致另一引用指向错误的值。
缓存哈希值
在Java中,string的哈希值经常被用。举个例子,在HashMap中。保持不变,可以保证总是返回相同的哈希值。所以它可以被缓存而不用担心被改变。 这意味这不需要在使用的时候每次都计算哈希值。这将更高效。
在String类中,它有以下的代码:
private int hash;//this is used to cache hash code.
使其他类的使用更加容易。
为了更具体,想想下面的程序:
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 属性。
安全
String 在很多java的类中,网络连接中,打开的文件中经常被作为参数使用。如果String是可以改变的,一个连接或者文件将有可能被改变,这将导致严肃的安全威胁。这个方法认为它正连接到一个机器,但是实际上不是。易变的strings将在反射或者作为参数将导致安全问题。
下面是代码实例:
boolean connect(string s){
if (!isSecure(s)) {
throw new SecurityException();
}
//here will cause problem, if s is changed before this by using other references.
causeProblem(s);
}
不变对象是自然线程安全
因为不可变对象是不可以改变的,它能够被多个线程自由的共享。这消除了同步。
总结
String被设计成不可以更改的是为了效率和安全。这也是为什么现在有很多不可以改变的类。