Java字符串对象和常量池的总结
字符串对象
new
当执行String str1= new String("123");
时,虚拟机会创建几个对象呢,答案是两个。
当一个字符串对象被new出来的时候,有两种情况:
当字符串常量池中已经有这个对象时,此时只会在堆里创建这一个对象;
当字符串常量池中没有这个对象时,那么虚拟机还会在字符串常量池中创建一个对象。
+
当采用了+号拼接两个字符串时,会新建几个对象呢?
- 情况1:常量+常量,编译器会优化成一个常量,如果这个常量在字符串常量池已经存在了,那么就不会创建对象,而如果字符串常量池中没有这个对象,那么就会在常量池中创建一个对象。
- 情况2:常量+变量||变量+变量,只要+号左右两边出现了变量,那么就会走StringBuilder拼接字符串,所以会新建一个Stringbuilder对象,并且调用StringBuilder的toString方法时,还会new一个String对象,所以这里会创建两个对象。(注意:StringBuilder的toString方法不会在字符串常量池生成对象,查看字节码指令发现并没有ldc这条指令)
常量池
在JDK7以前,字符串常量池在方法区的实现永久代里面的。
在JDK7以后,字符串常量池是在堆空间里面的。
为什么要放到堆里面?
- 如果还在方法区中,那么字符串常量池只有在Full GC执行时才会被垃圾回收,而如果在堆里,垃圾回收的效率大大增强,可以及时回收内存。
- 永久代默认情况下比较小,大量字符串容易导致OOM。
intern方法
当一个字符串对象执行了intern方法后
如果字符串常量池已经存在了该字符串,那么会返回常量池里对象的地址。
如果字符串常量池不存在该字符串
- JDK7以前,会在字符串常量池中生成一个新的对象。
- JDK7以后,会在字符串常量池中保存执行了intern方法对象的地址,即常量池里该字面量的地址和堆里对象的地址一样。
面试题