1. String 中 诡异的 intern() 方法

在学习String的intern()方法时,有一些疑惑和不解的地方,特此记录

  • intern()方法的官方描述

    如果一个字符串不存在常量池中,那么把其放入常量池,并返回指向常量池中该字符串的地址。

    如果其在常量池中,那么直接返回常量池中该字符串的地址。

    有以下代码段。

    其中第一个 == 判断显然是返回 false ,因为 s 指向堆中的字符串对象 "1",而 s2 指向字符串常量池中的 "1"。

    关键在于下面的一段代码,在 jdk6 和 jdk7/8 中的输出是不同的,在jdk6中输出 false ,在 jdk 7/8中输出true。

    乍一看,似乎和上面没有什么不同,只是 字符串由 "1" 变成了 "11", 那么结果不应该是还是为 false 吗,为什么

    jdk6 中是false ,jdk 7/8中会变成 true 呢? 为了明白这个问题,我们首先需要知道什么时候字符串常量会被放入字符串常量池中。

  • 字符串常量

    在上述代码的 String s = new String("1"); 时,字符串常量 "1" 被放入到了字符串常量池中,

    而在 代码 String s3 = new String("1") + new String("1"); 时,字符串 "11" 并未放入字符串常量池中。

    在jdk6中,由于 字符串常量池在 永久代中,因此在执行代码 s3.intern();时, 会将字符串 "11" 放入字符串常量池中

    那么自然,s4 会指向 字符串常量池中的 "11" , s3指向的是堆中的 字符串对象 "11" ,他们相比较,结果为false。

    在 jdk7/8 中,做了一个重大的改进,将 字符串常量池中 移动到了 堆中。 可能正是由于这点才会对 字符串 常量池做了一定的"优化",

    调用 intern()方法,如果该字符串在串池中,则返回该地址,否则,在字符串常量池中,生成一个指向该字符串对象的引用!

    具体可以参见下图:

    所以,该段代码在 在 jdk7/8 中 执行结果会为false.

  • 练习

    String s3 = new String("1") + new String("1");
          s3.intern();
          String s4 = "11";
          System.out.println(s3 == s4);//true
    
          String s5 = new String("1") + new String("1");
          s5.intern();
          String s6 = "11";
          System.out.println(s5 == s6);//false
          System.out.println(s5 == s3);//false
          System.out.println(s6 == s3);//true
          System.out.println(s6 == s4);//true
    

    根据上面的知识, 我们知道 s3和s4都指向堆中的 "11",故结果为 true

    s5指向自己创建的堆中的对象(和s3指向的不同),而s6指向的是s3指向的那个对象。

    因此 s5 == s6 为 false, s5 == s3为 false, 而 s6 == s3, s6 == s4返回 true

总结

posted @ 2021-02-03 17:43  echocxl  阅读(68)  评论(0)    收藏  举报