[细说Java](2)Java中字符串为什么是不可变的

最后更新于:2022-04-01 10:00:14

在Java中字符串(String)是一个不可改变的类。一个不可改变的类只是一个对象实例不可修改的简单类。当创建一个对象实例时,对象实例的所有信息都被初始化,并且信息不能被修改。对于不可改变的类来说还有很多优势。上一篇文章很好说明了为什么字符串被设计成不可改变的。只有你很好的掌握了内存,同步,数据结构等知识后,你才能很好的回答这个问题。 1.字符串常量池的需求 字符串常量区是方法区(Method Area)中一块特殊的存储区域。当一个字符串被创建,如果该字符串已经存在字符串常量区时,相应的返回存在字符串的引用,而不是去新创建一个新的对象返回它的引用。 下面的代码中只会在堆中创建一个字符串对象。 ~~~ String string1 = "abcd"; String string2 = "abcd"; ~~~ 下面的图能很好的说明: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba2a98c48c.jpg) 如果字符串是可以改变的,改动一个字符串的引用将会导致另一个引用出现错误值。 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 ?](http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/)
';