大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
原文:字符串常量池到底保存的是字符串对象还是字符串对象的引用?
结论
在 JDK 6 及以前版本,字符串常量池保存字符串对象;JDK 6 之后的版本中,既保存了字符串对象,又保存了字符串对象的引用。
证据
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
}
JDK 6 输出 : false false
JDK 7 输出 : false true
JDK 6
String s = new String("1");
这种创建字符串的方式实际生成了两个字符串对象。首先,构造器中传入一个字符串对象 1
,它被放在字符串常量池。然后 JVM 会在堆中再创建一个字符串对象 1
,字符串变量 s
指向堆中这个字符串对象 1
的首地址。
当调用 s.intern()
时,由于字符串常量池已经存在字符串 1
了,所以会将字符串常量池中的字符串对象 1
返回。(JDK 7 的情况有所不同,后面会讲。)
再通过 String s2 = "1"
来给变量 s2
赋值时,会将字符串常量池中对象 1
的首地址返回给 s2
。
由于 s
指向堆中字符串对象 1
的地址,而 s2
指向字符串常量池中 1
的地址,调用 s == s2
的返回值当然是 false
。
在 String s3 = new String("1") + new String("1");
中则涉及字符串常量池中的对象 1
以及拼接而成、保存在堆中的字符串对象 11
。当调用 s3.intern();
时,由于字符串常量池中没有 11
,此时会在字符串常量池中生成一个字符串对象 11
。
同理,由于 s3
指向堆中字符串对象 11
的地址,而 s4
指向字符串常量池中 11
的地址,调用 s == s2
的返回值当然是 false
。
JDK 7
判断 s==s2
与上文一致,但是在执行 s3.intern();
时,虽然字符串常量池中还没有字符串对象,由于在上一步 String s3 = new String("1") + new String("1");
中已经在堆中生成了一个字符串对象 11
,所以会将堆中的字符串对象的引用保存到字符串常量池。
这时调用 s3 == s4
,两者都指向的是堆中字符串对象 11
的首地址,所以返回值是 true
。
总结
在 JDK 6 中,当调用字符串的 intern()
时,若字符串常量池先前已创建出该字符串对象,则返回字符串常量池中该字符串对象的引用。否则,将该字符串对象添加到字符串常量池中,再返回该字符串对象的引用。
而在 JDK 7 中,当调用 intern()
时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,若该字符串对象已经存在于 Java 堆中,则将堆中对此对象的引用添加到字符串常量池中,然后返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。
引用
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/164768.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...