在Java中字符串(String)是一个不可改变的类。一个不可改变的类只是一个对象实例不可修改的简单类。当创建一个对象实例时,对象实例的所有信息都被初始化,并且信息不能被修改。对于不可改变的类来说还有很多优势。上一篇文章很好说明了为什么字符串被设计成不可改变的。只有你很好的掌握了内存,同步,数据结构等知识后,你才能很好的回答这个问题。
1.字符串常量池的需求
字符串常量区是方法区(Method Area)中一块特殊的存储区域。当一个字符串被创建,如果该字符串已经存在字符串常量区时,相应的返回存在字符串的引用,而不是去新创建一个新的对象返回它的引用。
下面的代码中只会在堆中创建一个字符串对象。
~~~
String string1 = "abcd";
String string2 = "abcd";
~~~
下面的图能很好的说明:
![](https://box.kancloud.cn/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/)
- 前言
- [Hibernate开发之路](1)Hibernate配置
- [Hibernate开发之路](2)Hibernate问题
- [Hibernate开发之路](3)基础配置
- [Hibernate开发之路](4)ID生成策略
- [Hibernate开发之路](5)联合主键
- [设计模式实践之路](1)单例模式
- [Java]UDP通信的简单例子
- [Java]套接字地址InetAddress讲解
- [Java开发之路](1)final关键字
- [Java开发之路](2)Java字符串
- [Java开发之路](3)Java常用类
- [Java开发之路](4)String、StringBuffer与StringBuilder详解
- [Java开发之路](5)异常详解
- [Java开发之路](6)File类的使用
- [Java开发之路](7)RandomAccessFile类详解
- [Java开发之路](8)输入流和输出流
- [Java开发之路](9)对象序列化与反序列化
- [Java开发之路](10)DOM解析XML文档
- [Java开发之路](11)SAX解析XML文档
- [Java开发之路](12)JDOM和DOM4J解析XML文档
- [Java开发之路](14)反射机制
- [Java开发之路](15)注解
- [Java开发之路](16)学习log4j日志
- [Java开发之路](18)关于Class.getResource和ClassLoader.getResource的路径问题
- [Java开发之路](19)Long缓存问题
- [Java开发之路](20)try-with-resource 异常声明
- [Java开发之路](21)Comparator与Comparable
- [Java]Java工程师成神之路
- [细说Java](1)图说字符串的不变性
- [细说Java](2)Java中字符串为什么是不可变的
- [细说Java](3)创建字符串是使用&quot; &quot;还是构造函数?