你的位置:首页 > Java教程

[Java教程]【Simple Java】为什么Java中字符串是不可变的


在Java中,字符串是一个不可变的类,一个不可变的类指的是它的实例对象不能被修改。所有关于这个对象的信息在这个对象被创建时已初始化,且它们不能被修改。不可变类有很多优势,这篇文章总结了字符串被设计成不可变类的原因。一个合理的解释依赖于对内存模型,同步,数据结构等的深度理解。

字符串常量池的需求

字符串常量池是方法区中的一块特别存储区域。当需要创建一个字符串时,如果它的值在字符串常量池中已存在,那么常量池中的该字符串引用将被直接返回,而不会创建一个新的字符串对象返回其引用。

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

如果字符串是可变的,那么通过一个引用改变字符串的值,其它该字符串对象的引用将得到错误的值。

缓存Hashcode

字符串的hashcode在java中经常被使用,如HashMap。不可变保证了hashcode会一直相同,所以它可以缓存起来而不需要担心改变。这也意味着,每次使用String的时候,不需要重新计算hashcode,这使得性能更加有效。

在String类中,有一个hash字段用于缓存hash code。

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";

在这个例子中,如果字符串是可变的,那么它的value会被改变,这将违背Set集合的设计(不允许重复元素)。当然,这仅仅是一个示例,实际情况,String是没有value字段的。

安全性

字符串作为参数被广泛使用,如网络连接,文件打开操作等。如果字符串是可变的,那么网络连接或者文件将会被改变,这将引起严重的安全威胁。某个方法被认为连接到某一台机器,但是却被改变了,连接到其它机器。在反射中,可变的字符串同样会引起安全问题,因为参数同样是字符串。

如下代码是一个例子:

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);}

不可变的对象天生线程安全

因为不可变对象不能被修改,它们可以被多线程共享,这消除了同步操作。

 

总的来说,字符串被设计成不可变是出于性能和安全考虑,这也是为什么通常不可变类比较受欢迎。

 

译文链接:http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/