字符串常量池到底保存的是字符串对象还是字符串对象的引用?

本文探讨字符串常量池保存的内容,结论是JDK 6及以前保存字符串对象,JDK 6之后既保存对象也保存引用。通过分析JDK 6和JDK 7中不同字符串创建和操作方式,阐述了不同版本调用intern方法时字符串常量池的处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:字符串常量池到底保存的是字符串对象还是字符串对象的引用?

结论

在 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 堆中,则将堆中对此对象的引用添加到字符串常量池中,然后返回该引用;如果堆中不存在,则在池中创建该字符串并返回其引用。

引用

深入解析String#intern

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值