String s = new String("abc") 这条语句创建的对象数量,可能是1个,也可能是2个。
核心关键在于:字符串常量池中是否已经存在字面量“abc”对应的对象。
当JVM编译期遇到字符串字面量 "abc" 时,会将其视作一个编译期常量,并尝试将其放入字符串常量池。具体过程如下:
- 检查池中是否存在:首先检查字符串常量池中是否已存在内容为“abc”的String对象。
- 决定是否创建:
- 如果不存在,JVM会在常量池中创建一个新的
String对象来代表这个字面量。
- 如果已存在,则直接引用池中已有的对象。
而new String("abc")中的new关键字,则必定会在Java堆(Heap)上显式地创建一个新的、独立的String对象,无论常量池中情况如何。
因此,该语句创建的对象总数分为以下两种情况:
情况一:常量池中原来没有“abc”
此时会创建 2个 String对象。
- 一个在字符串常量池中,由字面量
"abc"触发创建。
- 一个在堆(Heap) 上,由
new关键字创建。
情况二:常量池中原来已有“abc”
此时只会创建 1个 String对象。
- 仅在堆(Heap) 上创建新对象,常量池中的已有对象被直接引用。
为了更直观地理解,我们可以通过一个代码示例来验证:
public class StringCreationExample {
public static void main(String[] args) {
// 此行代码会确保“abc”存在于字符串常量池中
String s1 = "abc";
// 使用new关键字在堆上创建一个新的String对象
String s2 = new String("abc");
System.out.println(s1 == s2); // 输出 false
System.out.println(s1.equals(s2)); // 输出 true
}
}
输出结果:
false
true
结果分析:
s1 引用的是字符串常量池中的 "abc" 对象。
s2 引用的是通过 new String("abc") 在堆上创建的全新对象。
- 虽然两个对象存储的字符串值相同(
equals()比较为true),但它们是两个完全不同的对象,内存地址不同,因此 s1 == s2 比较引用时结果为 false。
理解这一过程有助于深入理解String类和字符串常量池的机制,这是掌握Java虚拟机(JVM)内存模型的重要基础。简而言之,new String("abc")创建的对象数量取决于常量池的初始状态,可能是1个(仅堆对象),也可能是2个(堆对象+常量池对象)。
|