【问题标题】:Comparing two strings with "==": when will it work?用“==”比较两个字符串:什么时候可以工作?
【发布时间】:2011-11-20 17:10:11
【问题描述】:

假设你有三个字符串,

String s1 = "string one";
String s2 = new String("string one");
String s3 = "string one";

我知道s1 == s2false 是真的,但我在某处读到s1 == s3true。它是否正确?为什么或为什么不?

【问题讨论】:

  • 它是否存在可能只是一时的兴趣,但你不应该这样做。 == 用于对象标识, 不是字符串比较。
  • @paxdiablo:如果您专门处理字符串文字,可以使用==。但是必须记录这通常是一件很痛苦的事情,因此更容易全面使用equals()
  • 是的,我知道这一切。我多年来一直在用 java 编程,只是想知道:)。好像不应该是这样的……

标签: java string object equals


【解决方案1】:

字符串字面量会自动被实习。因此 s1 == s3 为真。字符串既可以在字符串常量池中创建,也可以在堆空间中创建。如果实习生在堆中创建的字符串,该字符串将在字符串常量池中。

当您创建一个字符串字面量(String s1 = "string one")时,该字符串会在字符串常量池中创建。此外,字符串常量池不存储重复项。所以当你说,

String s1 = "string one";
String s3 = "string one";

s1 和 s3 都将指向字符串常量池中字符串的同一个实例。所以 s1.equals(s3) 将是真的。并且 s1 == s3 也是如此;因为两个指针都是一样的。

但是,当您使用“new”构造函数实例化字符串时

String s2 = new String("string one");

然后在堆空间中创建 s2。堆空间是与字符串常量池不同的内存区域

所以当 s1.equals(s2) 为真时,s1 == s2 为假;因为它们将指向不同的内存区域。

但是,您可以通过调用 intern() 函数来转换使用“new”构造函数创建的字符串,使其移动到字符串常量池中。所以s2.intern()会在字符串常量池中返回一个字符串;虽然 s2 最初是在堆中创建的。

【讨论】:

  • 我相信这仅在编译单元内是正确的?也就是说,我不相信更笼统的说法:A.x == B.x 一定是真的。
  • -1 表示误导性的、毫无意义的第一句话,并且没有提及字符串实习。
  • @matt,我正在输入并保存.. 最后我确实提到了 intern()。
  • @vivek_jonam:Java 字符串是不可变的。当然,您可以将s3 重新绑定到一个新字符串,但这不会影响s1 绑定到的字符串。
  • @pst:每个.class 文件都有自己的字符串常量池(因此,如果您在两个.class 文件中查看相同的字符串文字,您会看到重复),但是,在类加载时,字符串常量池中的所有内容都是 intern 的,因此等价的字符串将引用同一个字符串对象。
【解决方案2】:

是的,这是真的,因为字符串文字都是被实习的。阅读String.intern() 的文档了解更多详情。

因此,这些都是同一个对象(并且将与 == 进行比较):

s1
s3
s1.intern()
s2.intern()
s3.intern()

【讨论】:

    【解决方案3】:

    以上是如何。

    你应该知道为什么。

    A) 在编译时声明的字符串变量引用到常量池中的常量

    B) 方法 ref 到堆空间中对象的字符串变量结果。

    这都是因为 JVM 规范和它的内存设计。

    A) 是因为字符串是不可变的。当java编译类和jvm加载类时,jvm在编码时发现了一个你声明的String变量。因为它是常量,jvm把常量放到“Runtime Constant Pool”内存区。而且,常数是唯一的。

    B) 非常简单。因为 jvm 运行时变量使用堆空间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      • 2015-01-30
      • 1970-01-01
      相关资源
      最近更新 更多