繁体   English   中英

如何比较 Java 中的字符串?

[英]How do I compare strings in Java?

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

==不好吗? 什么时候应该使用,什么时候不应该使用? 有什么不同?

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

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

Objects.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类的同一个实例。 这是因为字符串文字——或者更一般地说,作为常量表达式值的字符串( 第 15.28 节)——是“内部的”,以便使用方法String.intern共享唯一实例。

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

其他需要考虑的方法

String.equalsIgnoreCase()忽略大小写的值相等。 但是请注意,此方法在各种与语言环境相关的情况下可能会产生意外结果,请参阅此问题

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

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

==比较对象引用。

.equals()比较字符串值。

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

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

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

(a==b) ===> 真

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

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

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

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

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

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

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

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

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

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

使用 == 运算符进行字符串比较时,您不是在比较字符串的内容,而是在实际比较内存地址。 如果它们都相等,则返回 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 快得多,因为您正在比较两个内存地址,但您需要确保代码没有在代码中创建新的 String 实例。 否则你会遇到错误。

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 为您进行真正的比较。

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

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

当您使用==运算符检查(比较)两个对象时,它会将地址相等性与字符串池进行比较。 如果两个 String 对象具有相同的地址引用,则返回true ,否则返回false 但是如果你想比较两个 String 对象的内容,那么你必须重写equals方法。

equals实际上是 Object 类的方法,但是它被重写到 String 类中,并给出了一个新的定义来比较 object 的内容。

Example:
    stringObjectOne.equals(stringObjectTwo);

但请注意它尊重字符串的情况。 如果您想要不区分大小写的比较,那么您必须使用 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

我同意zacherates的回答。

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

从 zacherates 示例:

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

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

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

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

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

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

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

==如果两个对象(NOT TALKING ABOUT PRIMITIVES)都指向同一个对象实例,则返回 true。 .equals()如果两个对象包含相同的数据,则返回 true equals()与 Java 中的==比较

这可能会帮助你。

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

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

显然==更快,但是如果您只想判断 2 个String是否包含相同的文本,在许多情况下会(可能)给出错误的结果。

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

不用担心性能。 鼓励使用String.equals()的一些事情:

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

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

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

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

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

if (string1.equals(string2))

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

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

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()

功能:

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);

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

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

  • 情况1

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

    原因:创建的不带 null 的字符串字面量存储在堆的 permgen 区域的字符串池中。 所以 s1 和 s2 都指向池中的同一个对象。

  • 案例2

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

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

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

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

如果java.lang.Object类中存在equals()方法,并且它应该检查对象状态的等价性! 这意味着,对象的内容。 ==运算符应检查实际对象实例是否相同。

例子

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

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");

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

运算符==始终用于对象引用比较,而 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)

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

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

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

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

在 Java 中,当==运算符用于比较 2 个对象时,它会检查对象是否引用内存中的同一位置。 换句话说,它检查这两个对象名称是否基本上是对同一内存位置的引用。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM