八股文——JAVA基础:String s1 = new String(“abc“);这句话创建了几个字符串对象?
这段代码创建一个或两个对象。
如果没有“abc”这个字符串对象,那么会在堆中创建一个对象实例,并且在常量池中创建该实例的索引。
如果已有"abc"这个字符串对象,那么常量池中不会再创建,只会在堆中创建一个对象。
需要记住,常量池只会节省字面量(非new出对象时)的内存,因为多个字面量共享同一个常量池内容(常量池实质上是基于哈希表的索引)。
你注意到的“矛盾”其实是字面量加载(由 ldc
或类加载器初始化)和 new String(...)
本身向常量池写入 (intern()
)之间的区别:
-
字符串字面量的加载
java
复制编辑
String s1 = new String("abc");
在编译后的字节码里,会有一条类似
asm
复制编辑
ldc "abc"
指令,这条指令会确保在类加载/链接阶段,JVM 会把字面量
"abc"
自动加入常量池(如果还不存在的话)。-
这一行为和你写不写
new String("abc")
是分开的:只要字节码中出现了"abc"
这个字面量,常量池就会有它。
-
-
new String(...)
创建堆对象,不修改常量池
紧接着,执行java
复制编辑
new String("abc")
会在堆上再开辟一个新
String
实例,用常量池中已有的那份字符数据来初始化它的内容。但这一过程并不会把新对象“放进”常量池——它只是读取池里的那份,而不是向池里写入。
所以,究竟创建几个对象?
-
常量池里是否已经有
"abc"
-
没有:在类首次加载时,
ldc "abc"
会导致池中新建一个String
对象——这是由字面量触发的。 -
已有:字面量加载这步被跳过,不再新建。
-
-
new String("abc")
-
始终在堆上创建一个新对象,不管常量池中有没有相同字面量
-