String常量池和堆内存
详细内容请看以下链接,下面为简略摘抄
https://blog.csdn.net/sinat_33921105/article/details/82192094
首先,看下面一道经典题目:
1.下面代码中创建几个对象?
String s1 = new String("hello");
String s2 = new String("hello");
答案是3个,首先判断字符串常量池中是否有"hello"对象,没有的话先在字符串常量池中创建一个,然new String()的时候又会在堆内存中创建两个。
然后,再看下面稍微复杂点的
2.下面代码中,又创建了几个对象?
public class TestString {
public static void main(String[] args) {
String s1 = "Java"; //1
String s2 = "从0到1"; //2
String s3 = s1 + s2; //3
String s4 = "Java从0到1"; //4
System.out.println(s3 == s4);
}
}
正确答案为6个。
首先,我们知道1、2、4三行代码在字符串常量池中创建了3个对象,重点是第3行代码,在编译阶段时不能确定s3的值,只有在运行时才能确定s3的值是“Java从0到1”,而这个字符串对象因为不是在编译期确定下来的,因此不会被放到字符串常量池中,会被放到堆中,这就又一个对象。到这里,已经创建了4个对象,然而这还没有结束。
下面说说字符串常量池到底存在在哪个位置,在jdk1.6及之前在方法区中,但是在jdk1.7及以后就放在了堆中,我们现在一般很少使用jdk1.6及之前的版本,因此现在讨论所说的字符串常量池除非特别说明jdk版本,否则默认是在堆中。因此字符串常量池其实就在堆中。回到上面第3行代码,s3是由s1和s2相加得到的,因s3最终是在常量池之外的堆中形成的,而s1和s2都是在常量池中,因此会将s1和s2拷贝一份到字符串常量池之外的堆中来形成s3。如下图所示:
因此加上两个拷贝的对象,上述代码中一共创建了6个对象!其中3个是编译时期创建在字符串常量池中的,1个是运行时期创建在字符串常量池之外的堆内存中,还有2个是从字符串常量池中拷贝到堆内存中的对象。
上面提到重点知识:
1.编译阶段确定的字符串才会被放到字符串常量池中。
2.字符串常量池在堆中。
3.运行阶段确定的字符串,如果需要字符串常量池中的对象,那么会拷贝一个对象到堆内存中。