结论
先说结论: 1个或者2个
先用调试工具验证结论
先看一段代码:
public class StringDemo {
public static void main(String[] args) {
String str = new String("a");
}
}
我们打开idea在第三行出打断点:
可以看到当我们没执行这句代码的时候,内存中的String类型对象是2003个,然后我们点击下一步:
当我们执行过那行代码看,内存中的String对象变成了2005个,所以我们可以得出结论,改行代码会创建两个String对象,但是我们再看一段代码:
public class StringDemo {
public static void main(String[] args) {
String a = "a";
String str = new String("a");
}
}
我们在第四行处打上断点并打开调试工具:
当我们还没执行那句代码中的时候,内存中的String对象是2004个,然后我们点击下一步:
我们发现执行过那句代码后,内存中的对象变成了2005个,仅仅增加了一个!
综上:我们得出结论String str = new String(“a”);这句代码创建了一个或者两个对象,但是原理又是什么样的呢?
原理
首先我们来看一行代码:
String a = "a";
这句代码创建了一个对象?答案是一个,我们把这句代码翻译成jvm指令如下:
0: ldc #2 // String a 常量池中取出a放入栈顶
2: astore_1 // 将str保存在局部变量表中
其中ldc就是从字符串常量池中拿出"a"对象,如果字符串常量池中没有该对象,则会创建一个放于字符串常量池中,由于这句代码是第一次执行,所以肯定是要创建一个对象放入常量池的.
然后我们再看一段代码:
public class StringDemo {
public static void main(String[] args) {
String str = new String("a");
}
}
该行代码对应的jvm指令如下(讲解放于注释中):
0: new #2 // class java/lang/String 注意看这里,创建了一个对象,此时还没调用构造所以该对象里是空的
3: dup // 这里是复制一份栈顶元素,再压入栈顶,用作调用构造函数(这里不懂的话没关系)
4: ldc #3 // String a 注意看这里!如果字符串常量池中没有"a" 会创建
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 调用构造方法
9: astore_1
好我们这边再解释一遍这些字节码吧
- 首先new这个指令是创建了个String对象放在堆中,但是还没有执行构造,所以该String对象里面是空的,注意这里已经创建了一个对象了.
- 然后执行ldc指令,因为在String str = new String(“a”);这句代码之前,咱们并没有把字符串"a"放入字符串常量池中,所以字符串常量池中没有"a"对象,所以需要创建这里又创建了第二个对象了.
- 然后调用String的构造方法初始化str对象,把"a"对象中的内容赋值给str对象.
- …
因此我们可以得出结论,如果单单只有 String str = new String(“a”);这样一句代码,该代码会创建两个对象.
我们下面进行修改代码:
public class StringDemo {
public static void main(String[] args) {
String a="a";
String str = new String("a");
}
}
这段代码在执行String str = new String(“a”);前有一句String a="a"代码,该代码可以提前创建"a"对象放于字符串常量池中,所以String str = new String(“a”);这时只创建了一个对象.
好了关于这个创建几个对象已经讲完了,有不对的地方麻烦指正一下,还有求一个小小的关注,可不可以,嘤嘤嘤