intern()在Java 6和Java 7中的行为不同

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (9)
class Test {
    public static void main(String...args) {
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1.intern());
        String s2 = "Goodmorning";
        if (s1 == s2) {
            System.out.println("both are equal");
        }
    }
}

此代码在Java 6和Java 7中产生不同的输出。在Java 6中,s1==s2条件返回false,在Java 7中s1==s2返回true。为什么?

为什么这个程序在Java 6和Java 7中产生不同的输出?

提问于
用户回答回答于

看起来JDK7以与以前不同的方式实习实习生。 我用build 1.7.0-b147测试了它,得到了“两者相等”,但是当它与1,6.0_24一起执行(相同的字节码)时,我没有收到消息。 它还取决于该String b2 =...行在源代码中的位置。以下代码也不会输出消息:

class Test {
   public static void main(String... args) {
      String s1 = "Good";
      s1 = s1 + "morning";

      String s2 = "Goodmorning";
      System.out.println(s1.intern());  //just changed here s1.intern() and the if condition runs true   

      if(s1 == s2) {
         System.out.println("both are equal");
      } //now it works.
   }
}

看起来好像intern没有在其字符串池中找到字符串之后,将实际的实例s1插入池中。当创建s2时,JVM使用该池,因此它获得与s1相同的引用。另一方面,如果首先创建了s2,则该引用将存储到池中。 这可能是因为将永久生成的Java堆从interned Strings中移出来的结果。

在此处找到:重要的RFE在JDK 7中解决

在JDK 7中,interned字符串不再分配在Java堆的永久生成中,而是分配在Java堆的主要部分(称为年轻人和老一代)以及由应用程序创建的其他对象中。此更改将导致更多数据驻留在主Java堆中,永久生成中的数据更少,因此可能需要调整堆大小。由于这种变化,大多数应用程序在堆使用中只会看到相对较小的差异,但是加载很多类或大量使用String.intern()方法的较大应用程序将会看到更显着的差异。

不知道这是否是一个错误,从哪个版本... JLS 3.10.5状态

显式实施计算字符串的结果与任何具有相同内容的预先存在的文字字符串是相同的字符串。

所以问题是如何解释,编译时间或执行时间:预先存在或不存在? 我更喜欢它在7之前实施的方式......

用户回答回答于

我们来从示例中省略不必要的细节:

class Test {
    public static void main(String... args) {
        String s1 = "Good";
        s1 = s1 + "morning";
        System.out.println(s1 == s1.intern()); // Prints true for jdk7, false - for jdk6.
    }
}

让我们考虑String#intern为一个黑匣子。基于几个测试用例运行,我会得出结论,实现如下:

Java 6: 如果池包含object等于this,则返回对该对象的引用,否则创建新的字符串(等于this),放入池中,并返回对创建的实例的引用。

Java 7: 如果池包含的对象等于this,则返回对该对象的引用,否则放入this池中,然后返回this

Java 6和Java 7都没有违反该方法的合约。

扫码关注云+社区