如何比较Java中的字符串?

How do I compare strings in Java?

到目前为止,我一直在程序中使用==操作符来比较所有字符串。但是,我遇到了一个bug,把其中一个改为.equals(),它修复了这个bug。

==坏了吗?什么时候应该使用,不应该使用?有什么区别?


==检验参考相等性(是否为同一对象)。

.equals()检验值是否相等(逻辑上是否"相等")。

objects.equals()在调用.equals()之前检查null,这样就不必(从jdk7开始提供,在guava中也提供)。

将EDCOX1的4内容与任何EDCOX1(5)的内容进行比较(可从Java 1.5获得)。

因此,如果要测试两个字符串是否具有相同的值,您可能需要使用Objects.equals()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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。字符串文字:

Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are"interned" so as to share unique instances, using the method String.intern.

类似的例子也可在JLS 3.10.5-1中找到。


==测试对象引用,.equals()测试字符串值。

有时看起来好像EDCOX1 0比较值,因为Java做一些幕后的东西,以确保相同的在线字符串实际上是同一个对象。

例如:

1
2
3
4
5
6
7
8
9
10
11
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()将导致异常:

1
2
3
4
5
6
7
8
String nullString1 = null;
String nullString2 = null;

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

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

因此,如果你知道fooString1可能是空的,那么就通过写信告诉读者

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

以下是较短的,但它不太明显,它检查null(从Java 7):

1
System.out.print(Objects.equals(fooString1,"bar"));


==比较对象引用。

.equals()比较字符串值。

有时,==给出了比较字符串值的幻象,如下所示:

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

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

(a==b)==>真

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

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

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

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

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

如果(a==b)===>错误。

1
2
3
4
5
                String Pool
    "test" <-------------------- a

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

虽然.equals()总是比较字符串的值,因此在这两种情况下它都是正确的:

1
2
3
4
5
6
7
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()总是更好的。


==运算符检查两个字符串是否完全相同。

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


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

当使用==运算符进行字符串比较时,您不会比较字符串的内容,而是实际比较内存地址。如果两者都相等,则返回"真"和"假"。而字符串中的equals则比较字符串内容。

所以问题是,如果所有字符串都缓存在系统中,那么为什么==返回false,而等于返回true?嗯,这是可能的。如果您创建了一个新的字符串(如String str = new String("Testing")),那么即使缓存中已经包含了一个具有相同内容的字符串,也会在缓存中创建一个新的字符串。简而言之,"MyString" == new String("MyString")总是返回false。

Java还讨论了函数String(),它可以在一个字符串中使用,使其成为缓存的一部分,因此EDCOX1(3)将返回true。

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


1
2
3
4
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"。引用是不同的,但内容是相同的。


是的,很糟糕…

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

等于为你做了真正的比较。


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


Java有一个字符串池,Java在该池中管理字符串对象的内存分配。在Java中看到字符串池

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

equals实际上是对象类的方法,但它被重写为字符串类,并给出了一个比较对象内容的新定义。

1
2
Example:
    stringObjectOne.equals(stringObjectTwo);

但请记住,它尊重字符串的情况。如果要进行不区分大小写的比较,则必须使用String类的EqualSignoreCase方法。

让我们看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
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


我同意扎切拉提的回答。

但你能做的是在非文字字符串上调用intern()

来自Zacherates的例子:

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

如果你实习的非文字字符串相等是true

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


EDCOX1 0比较Java中的对象引用,对于EDCOX1和4个对象也不例外。

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

如果使用EDCOX1(0)将两个EDCOX1的4个对象进行比较,结果是true,那是因为EDOCX1×4个对象被交互,并且Java虚拟机具有多个引用指向EDCOX1×4的同一个实例。我们不应该期望用==作为true来比较一个String对象,该对象包含与另一个String对象相同的内容。


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

如果两个对象(不讨论原语)指向同一对象实例,则==返回true。如果两个对象在Java中包含与EDCOX1和30相关的数据EDCOX1,30,则EDCOX1 1返回true。

那可能对你有帮助。


==执行引用相等性检查,这两个对象(本例中的字符串)是否引用内存中的同一个对象。

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

显然,==速度更快,但如果你想知道2个String是否持有相同的文本,在许多情况下会(可能)给出错误的结果。

当然,推荐使用equals()方法。

别担心性能。鼓励使用String.equals()

  • 执行String.equals()首先检查引用是否相等(使用==),如果两个字符串通过引用相同,则不进行进一步的计算!
  • 如果两个字符串引用不相同,String.equals()将接下来检查字符串的长度。这也是一个快速的操作,因为String类存储字符串的长度,不需要计算字符或代码点。如果长度不同,则不进行进一步检查,我们知道它们不能相等。
  • 只有到目前为止,这两个字符串的内容才会被实际比较,这将是一个简短的比较:并不是所有的字符都会被比较,如果我们发现一个不匹配的字符(在两个字符串中的同一位置),就不会再检查其他字符。
  • 当所有这些都说了又做了,即使我们保证字符串是实习生,使用equals()方法仍然不是人们可能认为的那种开销,这绝对是推荐的方法。如果您想要有效的引用检查,那么在语言规范和实现保证相同的枚举值将是相同的对象(通过引用)的情况下使用枚举。


    如果你像我一样,当我第一次使用Java时,我想使用"=="操作符来测试两个字符串实例是否相等,但不管是好是坏,这都不是Java中正确的方法。

    在本教程中,我将演示几种不同的方法来正确地比较Java字符串,从我大部分时间使用的方法开始。在这个Java字符串比较教程的末尾,我还将讨论为什么在比较Java字符串时,"=="操作符不起作用。

    选项1:与等值方法比较的Java字符串大部分时间(可能是95%的时间),我将字符串与Java字符串类的等值方法进行比较,如下所示:

    1
    if (string1.equals(string2))

    这个字符串等于方法查看两个Java字符串,如果它们包含完全相同的字符串,则它们被认为是相等的。

    用equals方法查看一个快速字符串比较示例,如果运行以下测试,则不会认为两个字符串相等,因为字符不完全相同(字符的大小写不同):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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,如本例中所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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方法,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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:与Ctraseto方法比较Java字符串

    还有一种比较常见的第三种方法来比较Java字符串,也就是使用String类CaseReto方法。如果两个字符串完全相同,CompareTo方法将返回值0(零)。下面是这个字符串比较方法的一个简单示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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对象类中包含了一个平等方法。每当您创建自己的对象,并且希望提供一种方法来查看对象的两个实例是否"相等"时,应该重写(并实现)类中的这个相等方法(以Java语言在String Error方法中提供此相等/比较行为的方式)。

    您可能想看看这个==、.equals()、compare to()和compare()。


    功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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()));
    }

    测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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);


    ==运算符检查两个引用是否指向同一对象。.equals()检查实际字符串内容(值)。

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

    • 案例1

      1
      2
      3
      4
      String s1 ="Stack Overflow";
      String s2 ="Stack Overflow";
      s1 == s2;      //true
      s1.equals(s2); //true

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

    • 案例2

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

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


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


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


    如果equals()方法存在于java.lang.Object类中,则需要检查对象状态的等效性!也就是说,对象的内容。而==操作符需要检查实际对象实例是否相同。

    例子

    考虑两个不同的参考变量,str1str2

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

    如果你使用equals()

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

    如果使用==,则输出为TRUE

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

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


    operator==始终用于对象引用比较,而string class.equals()方法则用于内容比较:

    1
    2
    3
    4
    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)

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

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


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

    一个关键的注意事项是,字符串存储在一个块池中,所以一旦创建了一个字符串,它就永远存储在同一个地址的程序中。字符串不变,它们是不变的。这就是为什么如果您有大量的字符串处理要做,那么使用常规的字符串连接是一个坏主意。相反,您将使用提供的StringBuilder类。记住,指向这个字符串的指针可能会改变,如果您有兴趣查看两个指针是否相同,那么执行==是一个很好的方法。字符串本身没有。


    在Java中,when the"=="社is used to出现2检查对象,它的对象,参见if the to see to the same在记忆的地方。在其他的话,它检查看如果names are the 2对象的same to the references基本存储的位置。P></

    the Java字符串类的equals()真的overrides the默认执行对象级和EN -茶overrides the method that only the values EN检查知道,not of the strings,在记忆的位置。This means that if You Call the method to equals()2出现的字符串对象,那么只要of characters is the actual序列都是平等的,平等的事情考虑的对象。P></

    The == operator checks if the two strings are exactly the same object.

    The .equals() method check if the two strings have the same value.