如何比较Java中的字符串?

sgtfey8w  于 2022-09-16  发布在  Java
关注(0)|答案(23)|浏览(167)

这个问题的答案是community effort。编辑现有答案以改进此帖子。它目前不接受新的答案或互动。

到目前为止,我一直在程序中使用==运算符来比较所有字符串。然而,我遇到了一个错误,将其中一个更改为.equals(),并修复了该错误。
==坏吗?什么时候应该使用,什么时候不应该使用?有什么区别?

jhdbpxl9

jhdbpxl916#

==测试参考相等性(是否为同一对象)。
.equals()测试值是否相等(是否逻辑上“相等”)。
物体。equals()在调用.equals()之前检查null,因此您不必这样做(从JDK7开始提供,也可以在Guava中使用)。
因此,如果要测试两个字符串是否具有相同的值,则可能需要使用Objects.equals()

// These two have the same value
new String("test").equals("test") // --> true 

// ... but they are not the same object
new String("test") == "test" // --> false 

// ... neither are these
new String("test") == new String("test") // --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" // --> true 

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

您几乎总是希望使用Objects.equals()。在罕见情况下,您知道**您正在处理内部字符串,您可以使用==
从JLS 3.10.5.字符串文本
此外,字符串文字总是指类String相同示例。这是因为使用String.intern方法,字符串文字(或者更一般地说,是常量表达式(§15.28)的值的字符串)被“内部”以共享唯一示例。
在JLS 3.10.5-1中也可以找到类似的示例。

考虑的其他方法

一串equalsIgnoreCase()值相等,忽略大小写。但是,请注意,这种方法可能会在各种与区域设置相关的情况下产生意外的结果,请参见this question
一串contentEquals()将String的内容与任何CharSequence(从Java 1.5开始提供)的内容进行比较。在进行相等性比较之前,不必将StringBuffer等转换为字符串,但将空检查留给您。

yhxst69z

yhxst69z17#

是的,==不适合比较字符串(任何对象,除非您知道它们是规范的)。==只是比较对象引用。.equals()平等性测试。对于字符串,它们通常是相同的,但正如您所发现的,这并不总是保证的。

fgw7neuy

fgw7neuy18#

是的,很糟糕。。。
==表示两个字符串引用是完全相同的对象。您可能听说过这种情况,因为Java保留了某种文字表(确实如此),但情况并非总是如此。一些字符串以不同的方式加载,从其他字符串等构建,因此您决不能假设两个相同的字符串存储在同一位置。
Equals为你做真正的比较。

dfuffjeb

dfuffjeb19#

String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true

确保你明白为什么。这是因为==比较仅比较参考;equals()方法对内容进行逐字符比较。
当您为ab调用new时,每一个都会获得一个指向字符串表中"foo"的新引用。参考文献不同,但内容相同。

fkaflof6

fkaflof620#

Java中的字符串是不可变的。这意味着无论何时尝试更改/修改字符串,都会得到一个新示例。无法更改原始字符串。这样做是为了缓存这些字符串示例。一个典型的程序包含大量的字符串引用,缓存这些示例可以减少内存占用并提高程序的性能。
使用==运算符进行字符串比较时,不是比较字符串的内容,而是实际比较内存地址。如果两者相等,则返回true和false。而字符串中的equals比较字符串内容。
所以问题是,如果所有字符串都缓存在系统中,为什么==返回false而equals返回true?嗯,这是可能的。如果您创建了一个新字符串,如String str = new String("Testing"),则最终会在缓存中创建一个新的字符串,即使缓存已经包含具有相同内容的字符串。简而言之,"MyString" == new String("MyString")将始终返回false。
Java还讨论了函数intern(),该函数可用于字符串,使其成为缓存的一部分,因此"MyString" == new String("MyString").intern()将返回true。
注意:==运算符比equals快得多,因为您正在比较两个内存地址,但您需要确保代码不会在代码中创建新的字符串示例。否则,您将遇到错误。

9vw9lbht

9vw9lbht21#

==运算符检查两个字符串是否完全相同。
.equals()方法将检查两个字符串是否具有相同的值。

ghhaqwfi

ghhaqwfi22#

==比较对象引用。
.equals()比较字符串值。
有时==会产生比较字符串值的错觉,如以下情况:

String a="Test";
String b="Test";
if(a==b) ===> true

这是因为当您创建任何字符串文字时,JVM首先在字符串池中搜索该文字,如果找到匹配项,则会对新字符串提供相同的引用。因此,我们得到:

(a==b)==>true

String Pool
     b -----------------> "test" <-----------------a

但是,==在以下情况下失败:

String a="test";
String b=new String("test");
if (a==b) ===> false

在这种情况下,对于new String("test"),语句新字符串将在堆上创建,并且该引用将被赋予b,因此b将被赋予堆上的引用,而不是字符串池中的引用。
现在a指向字符串池中的字符串,而b指向堆中的字符串。因此,我们得到:

如果(a==b)==>false

String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

.equals()始终比较字符串的值,因此在两种情况下均为真:

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

因此,使用.equals()总是更好。

ctrmrzij

ctrmrzij23#

==测试对象引用,.equals()测试字符串值。
有时看起来好像==比较值,因为Java做了一些幕后工作,以确保相同的内嵌字符串实际上是同一个对象。
例如:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

但是要小心空值

==可以很好地处理null字符串,但从空字符串调用.equals()将导致异常:

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

因此,如果您知道fooString1可能为空,请通过以下方式告诉读者

System.out.print(fooString1 != null && fooString1.equals("bar"));

以下内容较短,但不太明显,它检查空值:

System.out.print("bar".equals(fooString1));  // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar"));  // Java 7 required

相关问题