String对象的不可变性
在实现代码中,String类被final关键字修饰了。变量char数组也被final修饰了。
类被final修饰代表该类不可被继承,char[]被final+private修饰,代表String对象不可被修改。Java实现的这个特性叫做String对象的不可变性,即String对象一旦创建成功,就不能再对它进行改变。
Java这样做的好处是什么呢
第一,保证了String对象的安全性。假设String对象是可变的,那么String对象将可被任意修改。
第二,保证hash属性值不会被随意的变更,确保唯一性,使得类似HashMap的容器才能实现相应的key-value缓存功能。
第三,可以实现字符串常量池。在Java中通常有两种创建字符串对象的方式,一种是通过字符串常量的方式创建,如String str = "ABC"; 另一种是字符串变量通过new的方式进行创建,如 String str = new String("ABC");
当使用 String str = "ABC";方式进行创建字符串对象时,JVM首先会检查该对象是否在字符串常量池中,如果存在,则返回该对象的引用,否则新的字符串将在常量池中被创建。这中方式减少了同一个值的字符串对象的重复创建,节约内存。
String str = new String("ABC");这种方式首先在编译类文件时,"ABC"常量字符串将会放入到常量结构中,在类加载时,"ABC"将会在常量池中创建;其次,在调用new时,JVM命令将会调用String的构造函数,同时引用常量池中的"ABC"字符串,在堆内存中创建一个String对象;最后 str引用String对象。
String对象的优化
如何构建超大字符串
在实际操作中,我们对字符串的拼接是很常见的。
String str = "ab"+"cd"+"ef";
分析上述代码,首先会生成一个ab对象,再生成abcd对象,最后生成abcdef对象,这样的执行效率是很低的。
但是实际中,只会有一个对象生成,因为编译器自动优化了这段代码
String str = "abcdef";
以上是对字符串常量的累计,那么对于字符串变量的累计是什么效果呢?
String str = "abcdef";
for(int i = 0; i < 1000; i ++){
str = str + i;
}
上述代码经过编译后,编译器同样对这段代码进行了优化。在拼接时,偏向于使用StringBuilder,这样可以提高效率。
所以在进行大量的字符串拼接操作时,还是建议显示的使用StringBuilder来提高执行效率。
使用String.intern 节省内存
如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符添加到常量池中,并返回此String对象的引用。
与new String()比较的示例代码
String a = new String("abc").intern();
String b = new String("abc").intern();
System.out.println(a == b);
true
String q = new String("bcd");
String w = new String("bcd");
System.out.println(q == w);
false