为什么String在Java中是不可变的

来源:互联网 发布:淘宝直播主播排名榜 编辑:程序博客网 时间:2024/05/17 01:50

String在Java中是不可变类。一个不可变类简单来讲就是它的实例不可被修改。一个实例的所有信息在这个实例被创建时就被初始化,然后这些信息不能被修改。不可变类有很多优点。这篇文章介绍为什么String被设计成为不可变类。一个好的答案取决于对内存、同步、数据结构等的深入理解。

1.字符串池的需要

字符串池是在方法区的一块特殊的存储区域。当一个字符串被创建时,如果这个字符串已经存在于池中,将会返回一个这个已经存在的字符串的引用,而不是创建一个新的对象然后返回其引用。

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

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

如果一个字符串是可变的,那么改变这个字符串的引用将会导致另一个引用获取错误的值。

2.缓存哈希码

在Java中我们经常使用字符串的哈希码。比如,在一个HashMap中。把字符串变成不可变的能够保证哈希码的一致性,这样我们就不必担心其改变了。这也意味着,我们在使用HashMap时不要每次都重新计算哈希值。这样效率更高。

在String这个类中,存在这样的代码:

private int hash;//this is used to cache hash code.

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的设计(set包含不可复制的元素)。这个例子为了简单起见,在真实的String类中并没有value这个字段。

4.安全


String被用做很多Java类的参数,比如网络连接,打开文件等等。如果字符串是可变的,一个连接或文件将会被改变,这会引发一些列安全隐患。一个方法认为它连接到一台主机上,但实际上不是我们真正要连接的主机。可变的字符串也会在我们使用反射时其参数是字符串时引发严重的安全问题。
下面是一个例子:
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);}

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

因为不可变对象不能被改变,它们可以被多个线程共享。我们将不再需要引入同步来保证线程安全。
总的来说,出于效率和安全的考虑String被设计成不可变类。这也是不可变在很多场景下更受偏爱的原因。
0 0
原创粉丝点击