繁体   English   中英

为什么这些字符串的 str == str.intern() 结果不同?

[英]Why are the results of of str == str.intern() for these strings different?

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

结果:

 true
 false   

第一个打印true ,第二个打印false 为什么结果不同?

行为上的差异与StringBuilderStringBuffer之间的差异无关。

String#intern()的 javadoc 声明它返回

当调用 intern 方法时,如果池中已经包含一个等于该String对象的字符串equals(Object)equals(Object)方法确定equals(Object) ,则返回池中的字符串 否则,将此String对象添加到池中并返回对此String对象的引用。

从创建的String

String str2 = new StringBuffer("ja").append("va").toString();

是一个不属于池的全新String

为了

str2.intern() == str2

要返回falseintern()调用必须返回不同的引用值,即。 String "java"已经在池中

在第一次比较中,在调用intern()之前String “计算机软件”不在字符串池中。 因此intern()返回的引用与存储在str2引用相同。 因此引用相等str2 == str2返回true

因为您的作业不会从实习池中重新读取,并且 Java String (s) 是不可变的。 考虑

String str1 = new StringBuilder("计算机").append("软件").toString();
String str1a = new String(str1); // <-- refers to a different String 
str1 = str1.intern();
str1a = str1a.intern();
System.out.println(str1a == str1);
String str2 = new StringBuffer("ja").append("va").toString();
String str2a = new String(str2); // <-- refers to a different String 
str2 = str2.intern();
str2a = str2a.intern();
System.out.println(str2a == str2);

输出是(如您所料)

true
true

之前提到了很多关于池的答案,并使用 Oracle 链接文档进行了非常清楚的解释。

我只想指出我们在调试代码时可以检查的方式。

    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);//the str1.intern() returns the same memory address the str1
    String str2 = new StringBuffer("ja").append("va").toString();
    System.out.println(str2.intern() == str2);//the str2.intern() does not return the same memory address the str2

您可以使用任何IDE并调试来检查str1和str1.intern()/str2和str2.intern()的实际地址。

让我添加一些更有趣的东西:

  1. OpenJDK 8 是真的,真的;
  2. Oracle JDK 6 是真的,真的;

所以我认为正确的答案是:

不同供应商的 jvm 或 jvm 版本可能有不同的实现(语言规范不强制如何)

在 Oracle JDK 8 中(我猜你在使用):字符串“java”已经在池中(由 java.lang.Version#laucher_name 加载)并且字符串池只存储引用,而不是对象。

但是在 OpenJDK 中,laucher_name 是“openJDK”;在 Oracle JDK 6 及以下版本中,字符串池会将字符串对象复制到 itslef 中

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM