混淆字符串引用比较 == 和 intern

Confuse about String reference comparison == with intern

我读过这个 when should we use intern method of string on string constants 但对 String 还是不是很清楚 == 也可以与 intern() 进行比较。我有几个例子。谁能帮助我更好地理解这一点。

String s1 = "abc";
String s2 = "abc";
String s3 = "abcabc";
String s4 = s1 + s2;

System.out.println(s3 == s4);                            // 1. why false ?
System.out.println(s3 == s4.intern());                   // 2. why true ?
System.out.println(s4 == s1 + s2);                       // 3. why false ?
System.out.println(s4 == (s1 + s2).intern());            // 4. why false ?
System.out.println(s4.intern() == (s1 + s2).intern());   // 5. why true ?

这里有很多答案可以解释这一点,但让我再给你一个。

只有在两种情况下,字符串才会驻留在字符串文字池中:当加载 class 并且字符串是文字或编译时常量时。否则仅当您在字符串上调用 .intern() 时。然后该字符串的副本列在池中并返回。所有其他字符串创建都不会被保留。字符串连接 (+) 正在生成新实例,只要它不是编译时常量表达式*。

首先:永远不要使用它。如果您不理解它,则不应使用它。使用 .equals()。为了比较而对字符串进行实习可能比您想象的要慢,并且不必要地填充哈希表。特别是对于内容差异很大的字符串。

  1. s3 是来自常量池的字符串文字,因此被驻留。 s4 是一个不产生内部常量的表达式。
  2. 当您实习 s4 时,它与 s3 具有相同的内容,因此是相同的实例。
  3. 同s4,表达式不是常量
  4. 如果你 intern s1+s2 你得到了 s3 的实例,但是 s4 仍然不是 s3
  5. 如果你 intern s4 它与 s3 是同一个实例

还有一些问题:

System.out.println(s3 == s3.intern());       // is true
System.out.println(s4 == s4.intern());       // is false
System.out.println(s1 == "abc");             // is true
System.out.println(s1 == new String("abc")); // is false

* 编译时间常量可以是在串联两边都带有文字的表达式(如 "a" + "bc"),但也可以是从常量或文字初始化的最终字符串变量:

    final String a = "a";
    final String b = "b";
    final String ab = a + b;
    final String ab2 = "a" + b;
    final String ab3 = "a" + new String("b");
    System.out.println("ab == ab2 should be true:  " + (ab == ab2));
    System.out.println("a+b == ab should be true:  " + (a+b == ab));
    System.out.println("ab == ab3 should be false: " + (ab == ab3));

您必须知道的一件事是,字符串是 Java 中的对象。变量 s1 - s4 不直接指向您存储的文本。它只是一个指针,指示在 RAM 中的何处查找文本。

  1. 这是错误的,因为你比较的是指针,而不是实际的文本。文本是一样的,但这两个字符串是两个完全不同的对象,这意味着它们有不同的指针。尝试在控制台上打印 s1 和 s2,你会看到。

  2. 确实如此,因为Java对字符串做了一些优化。如果 JVM 检测到两个不同的字符串共享相同的文本,那么它们将位于 "String Literal Pool" 中。由于 s3 和 s4 共享相同的文本,它们也会在 "String Literal Pool" 中使用相同的位置。 inter()-方法获取对文字池中字符串的引用。

  3. 同1,你比较两个指针。不是文本内容。

  4. 据我所知,附加值不会存储在池中

  5. 与 2 相同。它们包含相同的文本,因此它们存储在字符串文字池中,因此共享相同的插槽。

首先,s1、s2 和 s3 在声明时位于实习生池中,因为它们是通过文字声明的。 s4 不在实习生池中。这就是实习生人才库开始时的样子:

"abc" (s1, s2)
"abcabc" (s3)
  1. s4 与 s3 不匹配,因为 s3 在实习生池中,但 s4 不在。
  2. intern() 在 s4 上被调用,因此它在池中查找等于 "abcabc" 的其他字符串并将它们作为一个对象。因此,s3和s4.intern()指向同一个对象。
  3. 同样,添加两个字符串时不会调用 intern(),因此它与 intern() 池不匹配。
  4. s4 不在实习生池中,因此它不匹配具有 (s1 + s2).intern() 的对象。
  5. 他们都是实习生,所以他们都在实习生池中寻找对方。