1

我读过这篇文章,我们什么时候应该在字符串常量上使用字符串的实习生方法,但仍然不太清楚 String == 也与实习生()比较。我有几个例子。有人可以帮助我更好地理解这一点。

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 ?
4

3 回答 3

3

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

只有在两种情况下,字符串才会被嵌入到字符串文字池中:加载类并且字符串是文字或编译时间常量时。否则只有当你调用.intern()一个字符串时。然后在池中列出该字符串的副本并返回。所有其他字符串创建都不会被实习。+只要不是编译时常量表达式*,字符串连接 ( ) 就会产生新实例。

首先:永远不要使用它。如果你不理解它,你不应该使用它。使用.equals(). 为比较而留存字符串可能比您想象的要慢,并且不必要地填充哈希表。特别是对于内容高度不同的字符串。

  1. s3 是来自常量池的字符串文字,因此被实习。s4 是一个不产生内部常量的表达式。
  2. 当您实习 s4 时,它与 s3 具有相同的内容,因此是相同的实例。
  3. 与 s4 相同,表达式不是常量
  4. 如果你实习 s1+s2 你会得到 s3 的实例,但 s4 仍然不是 s3
  5. 如果你实习 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));
于 2015-10-24T22:41:10.277 回答
0

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

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

  2. 确实如此,因为 Java 对字符串进行了一些优化。如果 JVM 检测到两个不同的字符串共享相同的文本,那么它们将位于“字符串文字池”中。由于 s3 和 s4 共享相同的文本,它们也将在“字符串文字池”中使用相同的插槽。inter() 方法获取对字面量池中字符串的引用。

  3. 与 1 相同。您比较两个指针。不是文本内容。

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

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

于 2015-10-24T22:42:54.537 回答
0

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

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