混淆字符串引用比较 == 和 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()
。为了比较而对字符串进行实习可能比您想象的要慢,并且不必要地填充哈希表。特别是对于内容差异很大的字符串。
- s3 是来自常量池的字符串文字,因此被驻留。 s4 是一个不产生内部常量的表达式。
- 当您实习 s4 时,它与 s3 具有相同的内容,因此是相同的实例。
- 同s4,表达式不是常量
- 如果你 intern s1+s2 你得到了 s3 的实例,但是 s4 仍然不是 s3
- 如果你 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 中的何处查找文本。
这是错误的,因为你比较的是指针,而不是实际的文本。文本是一样的,但这两个字符串是两个完全不同的对象,这意味着它们有不同的指针。尝试在控制台上打印 s1 和 s2,你会看到。
确实如此,因为Java对字符串做了一些优化。如果 JVM 检测到两个不同的字符串共享相同的文本,那么它们将位于 "String Literal Pool" 中。由于 s3 和 s4 共享相同的文本,它们也会在 "String Literal Pool" 中使用相同的位置。 inter()-方法获取对文字池中字符串的引用。
同1,你比较两个指针。不是文本内容。
据我所知,附加值不会存储在池中
与 2 相同。它们包含相同的文本,因此它们存储在字符串文字池中,因此共享相同的插槽。
首先,s1、s2 和 s3 在声明时位于实习生池中,因为它们是通过文字声明的。 s4 不在实习生池中。这就是实习生人才库开始时的样子:
"abc" (s1, s2)
"abcabc" (s3)
- s4 与 s3 不匹配,因为 s3 在实习生池中,但 s4 不在。
- intern() 在 s4 上被调用,因此它在池中查找等于 "abcabc" 的其他字符串并将它们作为一个对象。因此,s3和s4.intern()指向同一个对象。
- 同样,添加两个字符串时不会调用 intern(),因此它与 intern() 池不匹配。
- s4 不在实习生池中,因此它不匹配具有 (s1 + s2).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()
。为了比较而对字符串进行实习可能比您想象的要慢,并且不必要地填充哈希表。特别是对于内容差异很大的字符串。
- s3 是来自常量池的字符串文字,因此被驻留。 s4 是一个不产生内部常量的表达式。
- 当您实习 s4 时,它与 s3 具有相同的内容,因此是相同的实例。
- 同s4,表达式不是常量
- 如果你 intern s1+s2 你得到了 s3 的实例,但是 s4 仍然不是 s3
- 如果你 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 中的何处查找文本。
这是错误的,因为你比较的是指针,而不是实际的文本。文本是一样的,但这两个字符串是两个完全不同的对象,这意味着它们有不同的指针。尝试在控制台上打印 s1 和 s2,你会看到。
确实如此,因为Java对字符串做了一些优化。如果 JVM 检测到两个不同的字符串共享相同的文本,那么它们将位于 "String Literal Pool" 中。由于 s3 和 s4 共享相同的文本,它们也会在 "String Literal Pool" 中使用相同的位置。 inter()-方法获取对文字池中字符串的引用。
同1,你比较两个指针。不是文本内容。
据我所知,附加值不会存储在池中
与 2 相同。它们包含相同的文本,因此它们存储在字符串文字池中,因此共享相同的插槽。
首先,s1、s2 和 s3 在声明时位于实习生池中,因为它们是通过文字声明的。 s4 不在实习生池中。这就是实习生人才库开始时的样子:
"abc" (s1, s2)
"abcabc" (s3)
- s4 与 s3 不匹配,因为 s3 在实习生池中,但 s4 不在。
- intern() 在 s4 上被调用,因此它在池中查找等于 "abcabc" 的其他字符串并将它们作为一个对象。因此,s3和s4.intern()指向同一个对象。
- 同样,添加两个字符串时不会调用 intern(),因此它与 intern() 池不匹配。
- s4 不在实习生池中,因此它不匹配具有 (s1 + s2).intern() 的对象。
- 他们都是实习生,所以他们都在实习生池中寻找对方。