例子:
String a = “abc”;
String b = “abc”;
String c = new String(“abc”);
String d = c.intern();
这段代码(code)共创建了几个对象?
答:只创建了两个对象。
第一行创建了,(对象的引用变量a存在栈中,到常量池中找有没有“abc”,因为没有,所以直接在常量池中创建“abc”对象,然后栈中的a指向常量池中的“abc”)。
第二行(对象的引用变量b存在栈中)会在常量池中找有没有“abc”,有就把栈中的b指向常量池中的“abc”;没有就在常量池创建“abc”对象,再指向它。第一行常量池中有“abc“了,所以栈中的b直接指向常量池中的“abc”。
第三行,在栈中为c申请一个空间,在堆中开辟空间存放对象“abc”,然后把堆中存放“abc”的地址赋值给c,c指向堆中的“abc”对象。
第四行,(把堆中的对象值“abc”拷贝到常量池中),但是先判断常量池中有没有“abc”,因为有,所以直接让栈中的d指向常量池中已经存在的“abc”。如果没有,就将堆中这个对象“abc”值拷贝到常量池中并返回对象的引用d,d指向的是常量池中“abc”(JDK1.6及以前是这样做)【这里没创对象】
第四行,先判断常量池中有没有“abc”,因为有,所以直接让栈中的d指向常量池中已经存在的“abc”。如果没有,就将堆中再创一个对象“abc”并返回对象的引用(JDK1.7及之后是这样做,不再拷贝到常量池,而是堆中创建一个类,再直接返回堆中对象的引用)【这里没创对象】
总结:只有第一行,第三行创建了对象。一共创建了两个对象。
但是 : System.out.println(a==c); //打印的值是 false ,因为引用的是两个不同的对象,具 体原因,看我的另外文章。
System.out.println(a==b); //打印的值是 true,因为引用的是常量池中同一个对象。
补充:【JVM内存结构分为:堆、方法区、栈、本地方法栈、程序计数器】
{其中,常量池,属于方法区中的。}