String字符串常量池对象和引用
众所周知,jdk1.7中已经把字符串常量池从永久代中剥离出来,存放在堆空间中。
但是字符串常量池在堆中是怎样维护的,常量池中存的究竟是String对象的引用还是String对象?
我们都知道类似String str="xxx"
和String str=new String("xxx")
的创建过程是不一样的,引用比较也会有所差异。
下面是结合jmap -histo pid
简单测试的结果:
- 还待补充
- java version - jdk1.8
- String中 private final char value[]-jdk1.8 -> private final byte value[]-jdk1.9
public class StringTest {
public static void main(String[] args){
System.out.println("KKKKKKKK");
//String对象个数 1532 || char[] 1942
//下面依次新增语句查看java.lang.String和char[]中对象个数。
String str1="xyz"; //String对象个数: 1533 || char[] 1943
String str2="xyz"; //String对象个数: 1533 || char[] 1943
String str3="aa"+"bb"+"cc"+"dd"; //String对象个数: 1534 || char[] 1944
String str4=new String("oook"); //String对象个数: 1536 || char[] 1945
String str5=new String("oook"); //String对象个数: 1537 || char[] 1945
try{
Thread.sleep(30000);
}
catch(InterruptedException ex){
...
}
}
}
- 结果验证了以下结论:
- 字符串常量池中存储的是
char[]数组对象
和String对象的引用
的对应关系,String对象的引用
所指向的String对象创建在堆中- jmap -histo pid 中会包含常量池中的对象。
- char[]数组对象只会在常量池中创建, String对象中的value引用指向的是常量池中的char[]。
- String首先会根据字符值在常量池中维护的char[]列表中查找。
- str1 常量池中创建了
char[]数组对象
和String对象引用
的对应,String对象引用
指向的String对象创建在堆中,返回的是String对象引用
。- str2 找到常量池中的
char[]数组对象
和String对象引用
对应记录,直接返回的是String对象引用
。- str3 编译器做了优化。 常量池中创建了"aabbccdd"的
char[]数组对象
和String对象引用
的对应,String对象引用
指向的String对象创建在堆中,返回的是String对象引用
。- str4 常量池中创建了
char[]数组对象
和String对象引用
的对应,String对象引用
指向的String对象A
创建在堆中。 然后在堆中新建String对象B
,里面的value指向的是常量池中的char[]数组对象
,返回该String对象B
的引用。- str5 找到常量池中的
char[]数组对象
和String对象引用
对应记录。堆中新建String对象C
,里面的value指向的是常量池中的char[]数组对象
,返回该String对象C
的引用。
最终堆中(包含字符常量池)的图示为:
后面再补充下更多的测试结果。
补充引用间是否相等的对比结果,引用是否指向同一个对象的对比结果。
补充使用反射修改String对象中value的值等情况下的场景结果。
相关文档:
深入解析String#intern