如何比较Java中的字符串?


724

==到目前为止,我一直在程序中使用运算符比较所有字符串。但是,我遇到了一个错误,将其中一个更改为错误.equals(),并修复了该错误。

==坏?什么时候应该使用它,不应该使用它?有什么不同?


12
同样很高兴知道,如果您覆盖.equals()方法,请确保您覆盖.hashcode()方法,否则最终将违反等价关系b / w equals和hashcode。有关更多信息,请参阅Java文档。
Nageswaran 2013年

留下我对为什么==在对象上起作用的解释的链接:stackoverflow.com/a/19966154/2284641
Johannes H.

==有时会工作,因为java有一个String池,在这里它试图重用常用字符串的内存引用。但是==比较一下对象是相等的,而不是值是相等的…… .equals()您想使用的正确用法也是如此。
James Oravec

除非您喜欢追踪细微的错误并研究Java String Interning过程的复杂性,否则切勿使用==来测试String是否相同。"12"=="1"+2是错误的(可能)
奥德赛航班

Answers:


5558

== 测试引用是否相等(它们是否是同一对象)。

.equals() 测试值是否相等(在逻辑上是否为“相等”)。

Objects.equals()null在调用之前进行检查,.equals()因此您不必(在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起。字符串文字

而且,字符串文字总是引用class 的相同实例String。这是因为使用方法将字符串文字(或更广泛地说,是常量表达式的值的字符串(第15.28节))“ 插入 ”以便共享唯一的实例String.intern

JLS 3.10.5-1中也可以找到类似的示例。

其他要考虑的方法

忽略大小写的String.equalsIgnoreCase()值相等。

String.contentEquals()将的内容String与任何内容进行比较CharSequence(从Java 1.5开始可用)。使您不必在进行相等比较之前将StringBuffer等转换为String,但是将null检查留给了您。


3
如果==检查引用相等性,那么n == 5为什么有意义?5不是变量
Hrit Roy

2
@HritRoy因为==检查变量的。当您有一个对象时,引用该对象的变量会将对象的引用作为value。因此,在将两个变量与进行比较时,可以比较参考==。比较原始数据类型(例如)时int,情况仍然相同。类型的变量int将整数作为值。因此,您可以使用比较两个int的值==。如果int是变量或幻数的值,则无所谓。另外:一个参考只不过是一个数字,是指内存。
akuzminykh 8:54

718

==测试对象引用,.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"));

以下内容比较简短,但检查是否为null不太明显:

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

86
有时候看起来好像“==”比较值 - == 总是比较值!(只是某些值是引用!)
aioobe 2012年

6
is,没有isNullOrEmpty()的静态方法,也没有运算符的自定义重载,这使得Java的这一部分比C#或Python笨拙。而且由于Java没有扩展方法,因此您无法编写自己的实用程序来扩展java.lang.String。对?关于将子类继承为子类,添加该静态实用程序方法,然后始终使用MyString的任何想法?带有两个参数以进行空安全比较的静态方法也可以在该子类中使用。
Jon Coombs 2014年

7
Groovy使用安全导航操作符groovy.codehaus.org/…),使此操作变得容易一些?.。那将转换nullString1?.equals(nullString2);为一个完全为空的语句。但是,如果有帮助,它validString?.equals(nullString);仍然没有帮助-仍然会引发异常。
查尔斯·伍德

5
:短方法在Java中为空的比较字符串stackoverflow.com/questions/11271554/...
Vadzim

5
@JonCoombs Java支持子类化和创建自己的方法。但是由于某些原因,很少有类被标记为final,String是其中之一,因此我们无法扩展。我们可以在其中创建其他类并制作实用程序类,该类以两个字符串作为参数,并在那里实现我们的逻辑。同样,对于null检查其他一些库(例如spring和apache),也可以使用该库。
Panther

442

== 比较对象引用。

.equals() 比较字符串值。

有时==会产生比较String值的错觉,例如以下情况:

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

这是因为当您创建任何String文字时,JVM首先在String池中搜索该文字,并且如果找到匹配项,则将相同的引用赋予新的String。因此,我们得到:

(a == b)===>是

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

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

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

在这种情况下,new String("test")将在堆上创建新的String语句,并将对该引用提供给b,因此b将在堆上(而不是在String池中)提供一个引用。

现在a指向字符串池中的字符串,而b指向堆上的字符串。因此,我们得到:

if(a == b)===>否。

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

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

虽然.equals()总是比较String的值,所以在两种情况下它都为true:

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()总是更好。


3
.equals()比较两个实例,但是实现了equals来比较它们。那可能比较或不比较toString的输出。
雅各布(Jacob)2016年

3
@Jacob对象类.equals()方法比较实例(引用/地址),其中String类.equals()方法被覆盖以比较内容(字符)
Satyadev

1
很好地指出字符串池与Java堆的差异,因为它们肯定是相同的。在字符串池中,Java试图“缓存” String对象以节省内存空间,这String是众所周知的不可变的(我希望我在这里正确地说了)。另请检查stackoverflow.com/questions/3052442/…–
罗兰

1
这是我一直在寻找的答案。
Weezy

真是个好答案!
alwbtc


178

Java中的字符串是不可变的。这意味着每当您尝试更改/修改字符串时,您都会获得一个新实例。您不能更改原始字符串。这样做是为了可以缓存这些字符串实例。典型的程序包含很多字符串引用,对这些实例进行缓存可以减少内存占用并提高程序性能。

当使用==运算符进行字符串比较时,您不是在比较字符串的内容,而是在实际上比较内存地址。如果它们相等,则返回true和false。而equals in string比较字符串内容。

所以问题是,如果所有字符串都缓存在系统中,为什么==返回false,而返回true?好吧,这是可能的。如果像String str = new String("Testing")创建新字符串一样,即使缓存中已经包含具有相同内容的字符串,最终还是会在缓存中创建新字符串。总之"MyString" == new String("MyString")总会返回false。

Java还讨论了可以在字符串上使用以使其成为高速缓存一部分的函数intern(),因此"MyString" == new String("MyString").intern()它将返回true。

注意:==运算符比等于运算符快得多,因为您正在比较两个内存地址,但是您需要确保代码没有在代码中创建新的String实例。否则,您将遇到错误。


147
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()方法对内容进行逐字符比较。

当为a和调用new时b,每个引用都会获得一个新引用,该引用指向"foo"字符串表中的。引用不同,但是内容相同。


128

是的,这很糟糕...

==表示您的两个字符串引用是完全相同的对象。您可能已经听说过这种情况,因为Java保留了某种文字表(它确实这样做了),但事实并非总是如此。某些字符串以不同的方式加载,它们是由其他字符串等构成的,因此,您绝不能假定两个相同的字符串存储在同一位置。

等于为您做真正的比较。


124

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


118

Java有一个String池,Java在该池下管理String对象的内存分配。请参见Java中的字符串池

使用==运算符检查(比较)两个对象时,会将地址相等性比较到字符串池中。如果两个String对象具有相同的地址引用,则返回true,否则返回false。但是,如果要比较两个String对象的内容,则必须重写该equals方法。

equals 实际上是Object类的方法,但是将其重写为String类,并给出了一个新的定义来比较对象的内容。

Example:
    stringObjectOne.equals(stringObjectTwo);

但是请注意,它尊重String的情况。如果要区分大小写,则必须使用String类的equalsIgnoreCase方法。

让我们来看看:

String one   = "HELLO"; 
String two   = "HELLO"; 
String three = new String("HELLO"); 
String four  = "hello"; 

one == two;   // TRUE
one == three; // FALSE
one == four;  // FALSE

one.equals(two);            // TRUE
one.equals(three);          // TRUE
one.equals(four);           // FALSE
one.equalsIgnoreCase(four); // TRUE

7
我看到这是一个大问题的较晚答案。请问现有答案中未提及的内容?
Mysticial

6
他添加了@Mysticial equalsIgnoreCase,这可能对新手有帮助。
AmitG

103

我同意zacherates的回答。

但是您可以做的是调用intern()非文字字符串。

从zacherates示例:

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

如果您实习非字面性的String相等是true

new String("test").intern() == "test" ==> true 

8
这通常不是一个好主意。实习相对昂贵,并且(反常地)可以>>增加<<您的JVM的内存占用并增加GC成本。在大多数情况下,这些优势超过了==用于字符串比较的性能优势。
斯蒂芬·C

101

==比较Java中的对象引用,对象也不例外String

为了比较对象(包括String)的实际内容,必须使用equals方法

如果使用来比较两个String对象,==结果是true,那是因为String对象已被检查,并且Java虚拟机有多个引用指向的同一实例String。不应期望将String包含相同内容的一个String对象==与用于评估为的另一个对象进行比较true


99

.equals()比较类中的数据(假设函数已实现)。 ==比较指针位置(对象在内存中的位置)。

==如果两个对象(不讲主旨)都指向SAME对象实例,则返回true。 .equals()如果两个对象包含的数据Java中的相同,则返回trueequals()==

那可能对您有帮助。


95

==执行引用相等性检查,检查这两个对象(在这种情况下为字符串)是否引用内存中的同一对象。

equals()方法将检查两个对象的内容状态是否相同。

显然==速度更快,但是如果您只想知道2 Strings 是否包含相同的文本,则在很多情况下(可能)会给出错误的结果。

绝对equals()推荐使用方法。

不用担心性能。鼓励使用的一些方法String.equals()

  1. 的执行String.equals()参考平等首先检查(使用==),并且如果2个字符串相同参考,不执行进一步的计算!
  2. 如果两个字符串引用不同,String.equals()则接下来将检查字符串的长度。这也是一种快速的操作,因为String该类存储字符串的长度,而无需计算字符或代码点。如果长度不同,则不执行进一步检查,我们知道它们不能相等。
  3. 只有到了这一步,才可以实际比较这两个字符串的内容,这只是一种简略的比较:如果我们发现一个不匹配的字符(在两个字符串中的相同位置,则不是所有字符都将被比较) ),则不会再检查其他字符。

总而言之,即使我们保证字符串是实习生,使用该equals()方法仍然不是人们可能会想到的开销,绝对是推荐的方法。如果要进行有效的引用检查,则在语言规范和实现可保证相同的枚举值将是同一对象(通过引用)的情况下,使用枚举。


2
Obviously == is faster-实际上.equals(String)先执行==其他检查,然后说速度差不多。
拉兹尔·沙兹

2
public boolean equals(Object anObject) { if (this == anObject) { return true; } ...
拉兹尔·沙兹

82

如果您像我一样,当我刚开始使用Java时,我想使用“ ==”运算符来测试两个String实例是否相等,但是无论好坏,这都不是在Java中实现的正确方法。

在本教程中,我将演示几种正确地比较Java字符串的方法,从我通常使用的方法开始。在本Java字符串比较教程的最后,我还将讨论为什么在比较Java字符串时“ ==”运算符不起作用。

选项1:使用equals方法Java字符串进行比较大多数时候(可能是95%的时间),我将字符串与Java String类的equals方法进行比较,如下所示:

if (string1.equals(string2))

此String equals方法查看两个Java字符串,如果它们包含完全相同的字符串,则认为它们相等。

让我们看一个使用equals方法的快速String比较示例,如果运行了以下测试,则两个字符串将不被视为相等,因为字符并不完全相同(字符的大小写不同):

String string1 = "foo";
String string2 = "FOO";

if (string1.equals(string2))
{
    // this line will not print because the
    // java string equals method returns false:
    System.out.println("The two strings are the same.")
}

但是,当两个字符串包含完全相同的字符串时,equals方法将返回true,如以下示例所示:

String string1 = "foo";
String string2 = "foo";

// test for equality with the java string equals method
if (string1.equals(string2))
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

选项2:使用equalsIgnoreCase方法进行字符串比较

在某些字符串比较测试中,您将要忽略字符串是大写还是小写。当您要以不区分大小写的方式测试字符串是否相等时,请使用String类的equalsIgnoreCase方法,如下所示:

String string1 = "foo";
String string2 = "FOO";

 // java string compare while ignoring case
 if (string1.equalsIgnoreCase(string2))
 {
     // this line WILL print
     System.out.println("Ignoring case, the two strings are the same.")
 }

选项3:使用compareTo方法比较Java字符串

还有另一种比较不常见的比较Java字符串的方法,那就是使用String类的compareTo方法。如果两个字符串完全相同,则compareTo方法将返回值0(零)。这是此字符串比较方法的简要示例:

String string1 = "foo bar";
String string2 = "foo bar";

// java string compare example
if (string1.compareTo(string2) == 0)
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

当我写有关Java中的平等概念的文章时,必须注意Java语言在基本Java Object类中包含equals方法。每当创建自己的对象时,只要想提供一种方法来查看对象的两个实例是否相等,就应该在类中重写(并实现)此equals方法(以Java语言提供的相同方式) String equals方法中的这种相等/比较行为)。

您可能需要看一下== 、. equals(),compareTo()和compare()


5
用于字符串文字,例如String string1 =“ foo bar”; 字符串string2 =“ foo bar”; 您可以直接使用==运算符来测试内容是否相等
JAVA 2013年

1
在google apps脚本中,“ compareTo”不是可能的。我尝试过instaed“等于”这是唯一
可行的

77

功能:

public float simpleSimilarity(String u, String v) {
    String[] a = u.split(" ");
    String[] b = v.split(" ");

    long correct = 0;
    int minLen = Math.min(a.length, b.length);

    for (int i = 0; i < minLen; i++) {
        String aa = a[i];
        String bb = b[i];
        int minWordLength = Math.min(aa.length(), bb.length());

        for (int j = 0; j < minWordLength; j++) {
            if (aa.charAt(j) == bb.charAt(j)) {
                correct++;
            }
        }
    }

    return (float) (((double) correct) / Math.max(u.length(), v.length()));
}

测试:

String a = "This is the first string.";

String b = "this is not 1st string!";

// for exact string comparison, use .equals

boolean exact = a.equals(b);

// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote

float similarity = simple_similarity(a,b);

6
这与其他答案有何不同?以及为什么按照您的建议进行操作
user151019 2015年

2
@马克上的差异的问题==,并equals已经通过其他的解决办法回答,我只是提供了一个不同的方式在一个宽松的方式比较字符串
Khaled.K

77

==运营商检查,如果两个引用指向同一个对象或没有。.equals()检查实际的字符串内容(值)。

请注意,该.equals()方法属于类Object(所有类的超类)。您需要根据类要求重写它,但是对于String来说,它已经实现,并且它检查两个字符串是否具有相同的值。

  • 情况1

    String s1 = "Stack Overflow";
    String s2 = "Stack Overflow";
    s1 == s2;      //true
    s1.equals(s2); //true

    原因:不带空值创建的字符串文字存储在堆的permgen区域的字符串池中。因此s1和s2都指向池中的同一对象。

  • 情况二

    String s1 = new String("Stack Overflow");
    String s2 = new String("Stack Overflow");
    s1 == s2;      //false
    s1.equals(s2); //true

    原因:如果使用new关键字创建String对象,则会在堆上为其分配单独的空间。


53

==比较对象的参考值,而类中equals()存在的方法java.lang.StringString对象的内容(与另一个对象)进行比较。


15
不必挑剔,但是equals()for 的方法String实际上是在String类中,而不是在中Object。默认值equals()in Object不会比较内容是否相同,并且实际上在引用相同时仅返回true。
Jacob Schoen 2012年

1
@JacobSchoen:由于GrepCode关闭,以上链接不再起作用。这是等于实现的替代方法:[内联链接](zgrepcode.com/java/openjdk/10.0.2/java.base/java/lang/…
Amandeep Singh,

50

我认为定义a时就定义了String一个对象。所以你需要使用.equals()。当您使用原始数据类型时,必须==String(以及任何对象)一起使用.equals()


7
“ char []”不是原始数据类型!它是“ char”的数组。数组本身并不是原始数据类型。
基督教徒

48

如果该equals()方法存在于java.lang.Object类中,并且期望检查对象状态的等效性!也就是说,对象的内容。而==运营商预计将检查实际的对象实例是相同与否。

考虑两个不同的参考变量,str1以及str2

str1 = new String("abc");
str2 = new String("abc");

如果您使用 equals()

System.out.println((str1.equals(str2))?"TRUE":"FALSE");

您将获得与TRUE使用一样的输出==

System.out.println((str1==str2) ? "TRUE" : "FALSE");

现在,您将获得FALSEas输出,因为即使str1str2都指向两个不同的对象,即使它们都共享相同的字符串内容。这是因为new String()每次都会创建一个新对象。


43

运算符==始终用于对象引用比较,而String类.equals()方法被覆盖以进行内容比较

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)

40

.equals()由于Object包含一个.equals()返回布尔值的方法,因此保证所有对象都有一个方法。如果需要进一步定义,则子类的工作就是覆盖此方法。没有它(即使用==),仅检查两个对象之间的内存地址是否相等。字符串重写此.equals()方法,并且不使用内存地址,而是返回字符级别的字符串比较以确保相等。

一个重要的注意事项是,字符串存储在一个总池中,因此一旦创建了字符串,它将永远存储在同一地址的程序中。字符串不变,它们是不可变的。这就是为什么如果要处理大量的字符串时,使用常规的字符串连接是一个不好的主意的原因。相反,您将使用StringBuilder提供的类。请记住,指向此字符串的指针可以更改,并且如果您有兴趣查看两个指针是否相同的==话,这是一个很好的方法。字符串本身没有。


2
“一旦创建了字符串,它将永远存储在程序中的相同地址上” -这是绝对错误的。只有编译时常量字符串表达式(可能包含final String变量)和程序显式实习的字符串才存储在所谓的“集总池”中。String一旦没有其他活动对象像其他任何类型的对象一样,所有其他对象也将进行垃圾回收。同样,虽然整个实习机制必须具备不变性,但与此无关。
泰德·霍普

字符串比较是通过equals或equalsIgnoreCase方法完成的,该方法实际上是比较字符串的内容。但是==符号只是检查参考值。对于这种情况,来自字符串池的字符串文字可以正常工作。字符串s1 =新的String(“ a”); 字符串s2 =新的String(“ a”); 在这种情况下,s1 == s2为假,但s1.equals(s2)为真。
Shailendra Singh'7

39

您也可以使用该compareTo()方法比较两个字符串。如果compareTo结果为0,则两个字符串相等,否则比较的字符串不相等。

==比较了参考,不比较实际的字符串。如果确实使用创建了每个字符串,new String(somestring).intern()则可以使用==运算符比较两个字符串,否则只能使用equals()或compareTo方法。


35

在Java中,当使用“ ==”运算符比较两个对象时,它将检查对象是否指向内存中的同一位置。换句话说,它检查两个对象名称是否基本上是对相同内存位置的引用。

Java String类实际上覆盖了Object类中默认的equals()实现,并且覆盖了该方法,以便它仅检查字符串的值,而不检查它们在内存中的位置。这意味着,如果调用equals()方法比较2个String对象,则只要实际字符序列相等,就将两个对象视为相等。

==运营商的检查,如果两个字符串是完全相同的对象。

.equals()方法检查两个字符串是否具有相同的值。


1
除非其中之一为null,否则如果s为null,则s.equals(s2)将崩溃,从而导致比较失败。当然,这并不与答案矛盾。这只是一个警告。
乔恩·库姆斯

1
不,它不会崩溃,它会引发NullPointerException,从而导致无法进行比较。
Bludzee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.