本篇文章内容参考自:
http://blog.csdn.net/renfufei/article/details/16808775
http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/
http://www.jb51.net/article/49092.htm
JAVA中的String是一个不可变(immutable)类,即创建一个String对象后,是不能直接改变字符串中的某个字符的。
我们打开JDK中String类的源代码来看一下:
<span style="font-family:Microsoft YaHei;">/** The value is used for character storage. */
private final char value[];</span>
其中用于存储String值的仍然是一个char型数组,并且注意到它是final修饰的,不可更改。
那么接下来思考为什么JAVA要把字符串设计成不可变类呢?有什么好处呢?
百度到了这样的文章:点击打开链接
文章说的非常好,建议阅读,我在这里再为大家总结一下:
String类是不可变类型的好处主要体现在两方面:效率、安全。
效率方面:
1、因为对象不可变,所以可以使用常量池的方式优化效率。在拷贝或者创建内容相同对象时,就不必复制内容本身,而是只要复制它的地址即可,复制地址只需要很小的空间和时间。只有不可变对象才能使用常量池,因为可以保证引用同一常量值的多个变量不产生相互影响。
2、因为对象不可变,所以String对象可以自身缓存HashCode。Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码. 在String类的定义中有如下代码:
<span style="font-family:Microsoft YaHei;">private int hash;//用来缓存HashCode </span>
安全性方面:
1、String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。
假如有如下的代码:
<span style="font-family:Microsoft YaHei;">boolean connect(string s){
if (!isSecure(s)) {
throw new SecurityException();
}
// 如果在其他地方可以修改String,那么此处就会引起各种预料不到的问题/错误
causeProblem(s);
} </span>
下面来详细分析一下常量池的思想,首先看常量池的示意图:
很明显只有不可变对象使用常量池,不然修改变量string1的值,string2的值也发生变化了。常量池的存在无疑大大降低了创建、拷贝等操作的时间复杂度和空间复杂度。由于平常编写的程序中,70%都是对字符串的操作,所以这个优化可以大大提升效率。
下面做实验体验这一点:
前三行打印结果为true,即s1、s2引用的对象的地址一样,说明两点,一是String类确实是不可变类,"ab"+"cd"被当做了新字符串而不是续接"ab"(不然"ab"和"abc"肯定不会地址一样),二是常量池确实存在,同是"abcd",所有对"abcd"的引用都指向同一地址。
后三行打印结果为false,原因应该是编译时,用new创建新对象会先于常量池判断,直接分配新地址。而这种写法很明显违背常量池设计初衷,所以我们可以看到IDE强力不推荐这种写法。
欢迎补充雅正!