1.基本概念
可变类:当获得这个类的一个实例引用时,可以改变这个实例的内容。
不可变类:不可变类的实例一但创建,其内在成员变量的值就不能被修改。其中String类就是不可变类的经典应用。
2.例子
下面我们通过一个例子来解释String的不可变性。
- String s = "abcd";
上面的语句定义了一个字符串变量s,该变量指向字符串“abcd”,当初始化变量s时,会在堆中为s分配内容空间,如下图所示:
- String s2 = s;
上面的语句是将字符串变量,赋值给另一个字符串变量。此时,s2和s是相同的字符串对象,如下图所示:
- s = s.concat("ef");
通过上面的语句,s就将指向新的字符串, 如下图所示:
当一个字符串在堆中被分配内容时,它就是不可变的,任何String的方法都无法改变字符串本身,但它可以返回一个新的字符串对象。如果需要可以修改的字符串对象,可以使用StringBuffer和StringBuilder,StringBuffer是线程安全的。由于StringBuilder不需要进行同步操作,StringBuilder是比较快速的。
3.String不可变性的原因
- 字符串池(String pool)。当初始化一个字符串变量时,如果字符串已经存在,就不会创建一个新的字符串变量,而是返回存在字符串的引用。 例如:String string1="abcd"; String string2="abcd"; 这两行代码在堆中只会创建一个字符串对象。如果字符串是可变的,改变另一个字符串变量,就会使另一个字符串变量指向错误的值。
- 缓存字符串hashcode码。字符串的hashcode是经常被使用的,字符串的不变性确保了hashcode的值一直是一样的,在需要hashcode时,就不需要每次都计算,这样会很高效。
- 出于安全性考虑。字符串经常作为网络连接、数据库连接等参数,不可变就可以保证连接的安全性。
4.总结
String的不变性在面试的过程中会经常被问到,所以我们不仅要知道String是不变的,还必须要清楚其中的原因,更重要的是也要晓得为啥要把String做成不可变的。当然,StringBuffer和StringBuilder同样提供了可变的字符串。会在后期讨论这两个对象。//TODO 另外两个String对象的讨论