String.intern()分析jdk1.6和1.7后变化

13 篇文章 2 订阅
  • 先看如下代码输出结果

        String str = new StringBuilder("11").append("va").toString();
        System.out.println(str.intern() == str);

        System.out.println("---------------------");

        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(str2.intern() == str2);

  • 在jdk1.6中运行,会得到两个false。在jdk1.7之后运行,第一个true,第二个false.
    因为在1.6中intern()会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中的这个新实例对象的引用。所以此时两者不相等。
  • 在1.7之后,永久代开始移除(1.8中彻底移除永久代),JDK 1.7 和 1.8将字符串常量由永久代转移到堆中,此时intern实现不再复制实例,如果该实例在常量池中首次出现,只是在常量池中记录该实例引用,因此intern返回的引用和原来StringBuilder创建的字符串实例是同一个。对于第二个Str2,因为StringBuilder创建的最终创建的"java"已经在StringBuilder.toString之前在常量池中出现过,所以不是首次出现,intern就会直接返回在常量池中的实例引用,而StringBuilder创建的是在堆内存中新的实例,因此两者不想等。可以用如下方式证实
        String str = new StringBuilder("11").append("va").toString();
        System.out.println(str.intern() == str);

        System.out.println("---------------------");

        String str3 = new String("xxxs");
        System.out.println(str3.intern() == str3);
  • 输出:
true
---------------------
false
  • 解析:
    第一个返回true,解释如上。
    第二个同样是new的一个字符串,StringBuilder.toString底层代码也是new一个对象,但为什么返回false呢。 因为在new String(“xxxs”)中,引号部分"xxxs"已经先在常量池中开辟空间存储了,然后再是在堆中存储,所以Str3.inter,不再是首次出现在常量池,因为返回的是常量池中实例的引用,自然和堆中的引用不同,因此是false.
    注:可以打印这些字符串的真实的地址identityHashCode(不能取hashcode,因为String重写了hashcode方法),,identityHashCode相同的,两个对象就相等。
       String str = new StringBuilder("11").append("va").toString();
        // "11va"第一次在常量池中出现,只记录引用,不会copy实例(1.7之前的会copy)
        System.out.println(System.identityHashCode(str.intern()));
        System.out.println(System.identityHashCode(str));
        System.out.println(str.intern() == str);

        System.out.println("-------------");

        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(System.identityHashCode(str2.intern()));
        System.out.println(System.identityHashCode(str2));
        System.out.println(str2.intern() == str2);

        System.out.println("-------------");

        String str3 = new String("xxxs");
        // str3.intern()之前,"xxxs"已经定义在常量池中
        System.out.println(System.identityHashCode(str3.intern()));
        System.out.println(System.identityHashCode(str3));
        // "xxxs"已经在常量池中存放,返回常量池中的引用
        System.out.println(str3.intern() == str3);

        System.out.println("-------------");

        System.out.println(str3.intern() == "xxxs");
  • jdk1.7和1.8运行结果如下:
31786283
31786283
true
-------------
11950696
32087476
false
-------------
7392722
30982214
false
-------------
true
  • jdk1.6运行结果:
9023134
19336051
false
-------------
6336176
23899971
false
-------------
6718604
8918002
false
-------------
true

原文:
因为JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串的实例的引用,而StringBulder创建的字符串实例在Java堆上,所以必然不是同一个引用,将返回false。
在JDK1.7中,intern()的实现不会在复制实例,只是在常量池中记录首次出现的实例引用,因此返回的是引用和由StringBuilder.toString()创建的那个字符串实例是同一个。

附:java关键字位置:
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EmineWang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值