一、String的基本特性
1、底层结构
- jdk1.8及以前,采用char[] 数组保存
- jdk1.9及以后,采用byte[]数据保存
2、不可变性
- 当对字符串重新复制时,需要重写指定内存区域复制,不能使用原有的value进行赋值
- 当堆现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
- 当调用String的replace()方法修改指定字符或字符串时,需要重新指定内存区域赋值,不能使用原有的value进行赋值
3、字符串常量池不能存储相同内同的字符串
- jdk1.6中字符串常量池的大小为1009,jdk1.7及以后大小为60013
- -XX:StringTableSize=100,可以通过这个参数修改字符串常量池的大小
二、String的内存分配
1、变迁史
关于字符串常量池的变迁史可以参考方法区的变迁史。
为什么会有这个变迁史?
(1)永久代的默认比较小
(2)永久代的垃圾回收频率低
三、String的基本操作
四、字符串拼接操作
先上结论:
- 常量与常量的拼接结果在常量池,原理是编译器优化
- 常量池中不会存在相同内容的常量
- 只要其中一个是变量,结果就在堆中,拼接的原理是StringBuilder
- 如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回对象地址
下面是一下例子:
@Test
public void test1(){
String str1 = "a" + "b";
String str2 = "ab";
System.out.println(str1 == str2); //true
System.out.println(str1.equals(str2)); //true
}
@Test
public void test2(){
String s1 = "java";
String s2 = "Python";
String s3 = "javaPython";
String s4 = s1 + "Python";
String s5 = s1 + s2;
String s6 = s4.intern();
System.out.println(s3 == s4); //false
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //true
}
/*
s1+s2由于是变量拼接,底层调用的是StringBuilder,返回前调用StringBuilder.toString()
*/
@Test
public void test3(){
String s1 = "a";
String s2 = "b";
String s3 = "ab";
String s4 = s1+s2;
System.out.println(s3 == s4); //false
}
五、intern()的使用
1、先说两个问题
在说intern()方法之前,先说两个问题:
(1)new String("ab")会创建几个对象? 答案:2
(2)new String("a")+new String("b")会创建几个对象?答案:6
先说第一个:
对象1:new关键字在堆空间创建的
对象2:字符串常量池中的ab
有了第一个的基础,再说第二个:
对象1:由于是变量拼接,所以会先new StringBuilder()
对象2:new String("a"),堆中
对象3:常量池中的“a”
对象4:new String("b"),堆中
对象5:常量池中的“b”
对象6:通过StringBuilder.toString()方法创建的 new String("ab"),特别注意这个在字符串常量池中没有创建“ab”
2、intern()方法的使用结论
先说intern()方法的使用结论:
- jdk1.6中,将这个字符串对象尝试放入字符串常量池
- 如果字符串常量池中(永久代)有字符串对象,则不会放入,返回的是已有字符串常量池中的对象的地址
- 如果字符串常量池中没有字符串对象,会把此对象复制一份放入常量池,并返回常量池中的对象地址
- jdk1.7及以后,将这个字符串对象尝试放入字符串常量池
- 如果字符串常量池(堆)中有字符串对象,则不会放入,返回的是已有字符串常量池中的对象的地址
- 如果字符串常量池中没有字符串对象,则会把对象的引用地址复制一份放入常量池,并返回常量池中的引用地址
3、补充使用例子
先上代码:
String s1 = new String("a") + new String("b");
String s2 = s1.intern();
System.out.println(s1 == s2); //jdk1.6 false jdk1.7 true
上面的代码在不同jdk版本中,得到的结果不同。