String::intern()和字符串常量池的理解

首先区分一个概念,运行时常量池是方法区的一部分,他包括了字面量(也就是字符串常量池)以及符号引用。Class文件里面也有一个常量池表,但是运行时常量池相比它来说可以动态添加,也就是说在运行的时候可以动态添加新的常量到常量池,使用的就是String类的intern().

 

在JDK6之前运行时常量池都是在方法区的,但是在JDK7之后,将字符串常量池从方法区移到了JAVA堆中,运行时常量池剩下的东西还在方法区。具体来说就是JDK1.6中,字符串常量池里面会保存各种字符串(以字符串对象实例的形式保存),但是在jdk1.7中是以实例的引用的形式保存。

 

String::intern()方法:如果在字符串常量池中,已经包含了这个String对象表示的字符串,那么返回代表池中的这个字符串的String对象的引用。否则会将这个对象表示的字符串添加到常量池,然后返回这个String对象的引用。(似乎也不能这么说,因为JDK7里面存放的是首次出现的实例的引用,并非把对象直接放进去了)


举个例子

public class RuntimeConstantPoolOOM{
    public static void main(String[]args){
               public static void main(String[]args){
                           String str1=new StringBuilder("计算机").append("软件").toString();
                           System.out.println(str1.intern()==str1);
                           String str2=new StringBuilder("ja").append("va").toString();
                           System.out.println(str2.intern()==str2);}}}

以上代码在JDK6里面的输出为:false 和false。因为在JDK6里面,会把首次遇到的字符串实例复制到字符串常量池中,返回的也是常量池中的字符串实例。而上面的StringBuilder创建的对象是在JAVA堆上的,也就是说虚拟机栈里面的str1变量是java堆里面的对象的引用,而str1.intern()返回的是方法区的字符串常量池里面的实例的引用。因此这两个都返回false。

而如果在JDK7里面,返回:true false。在JDK7里面,字符串常量池被移到了java堆,里面保存的不再是实例,而是第一次出现的实例的引用。而intern()返回的也是第一次出现的对象的引用,这两个引用指向的都是相同的实例。而“java”这个字符串在执行StringBuilder命令之前就已经存在在字符串常量池里面的,因此他不是首次出现,返回的就不是这次创建的对象(而是首次创建的对象),因此虽然str2还是指向JAVA堆里面的刚创建的对象,但是和intern()返回的引用不是同一个,因此为false。(因此可以利用intern来减小String对象所占的内存空间)

还需要注意的是

参考:https://www.jianshu.com/p/0d1c003d2ff5

https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html

https://blog.csdn.net/hqweay/article/details/88753035

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值