Java中比较两个字符串是否相等时使用“==”为什么返回false?

45

String parts is String[6]:

["231", "CA-California", "Sacramento-155328", "aleee", "Customer Service Clerk", "Alegra Keith.doc.txt"]

But when I compare parts[0] with "231":


但是当我将 parts[0]"231" 进行比较时:
"231" == parts[0]

上述结果是错误的,

我感到困惑,所以有人可以告诉我为什么吗?


5
@PaulJWilliams - 它确实给出了一个答案:这个问题。 :) - Corin
我想知道为什么数组中的字符串没有被内部化,如果使用字符串字面量创建数组,则引用比较不应该成功吗? - Sergio
1
避免使用“只是试着谷歌一下”的讽刺话语,因为将来你的嘲讽可能会成为谷歌搜索结果中的首位。就像现在一样。(需要知道答案并不意味着你是一个菜鸟...我最近在多种编程语言之间切换,我记不得哪些语言允许我对字符串执行 == 操作,哪些不允许。而那些不允许的语言中,我唯一还记得正确语法的语言是C。Java中有strcmp吗?呵呵...) - user435779
检查您是否使用new关键字初始化了String数组。如果您使用new关键字初始化String数组,它将不起作用,因为new总是创建新的引用。所以请使用这种方式:String[] array={"231", "CA-California", "Sacramento-155328", "aleee", "Customer Service Clerk", "Alegra Keith.doc.txt"}; String str="234"; if(str == array[0]){ System.out.println("Works"); } - Navin a.s
12个回答

78
< p > == 运算符比较对象引用,而不是String的值。

要比较String的值,请使用String.equals方法:

"231".equals(parts[0]);

在Java中,对于任何其他对象,比较值时始终使用equals方法而不是使用==运算符是正确的。

equals方法是Object的一部分,应该被需要以某种方式进行比较的类覆盖。


14

如果字符串没有被整合,那么==会检查引用标识。使用:

 "231".equals(parts[0]);

改为使用“instead”。


2
如果提到字符串字面量相互比较时返回 true,可以加 1 分。我的一个学生不相信 == 不会检查字符串的实际内容,因为他给我的每个例子都使用了字符串字面量并返回了 true。 - user120587
@Yishai,如果使用字符串字面量创建数组,为什么数组中的字符串没有被内部化? - Sergio
@Sergio,我想这个问题是故意设计成那样的,只是列出数组的内容,而不是它们是如何创建的。 - Yishai
我想说的是,如果使用以下方式创建字符串:string=new String[]{"231"}[0];,那么它不会被放入字符串池中。我不知道为什么,因为该字符串在代码中是硬编码的(数组使用了字符串字面量)。 - Sergio
@Sergio,如果你是基于这个问题来说的话,我认为事实并不是那样的,只是楼主简化了问题。如果你遇到过类似的情况,那我就不清楚了。 - Yishai
令人惊讶的是,如果字符串按照我上面说的方式创建,它不会被池化。我想单独提出一个问题询问原因。 - Sergio

13
以下代码将输出"true":
String s = "231";
if(s == "231")
{
    System.out.println("true");
}
else
{
    System.out.println("false");
}

这是因为字符串是不可变的,而Java会尽可能地节省空间,因此它会将两个字符串指向同一个内存引用。

然而,以下代码输出"false":

String s = new String("231");
if(s == "231")
{
    System.out.println("true");
}
else
{
    System.out.println("false");
}

new会强制将字符串存储在新的内存位置。

顺便说一下,您应该始终使用.equals()来比较字符串(就像这种情况一样)。


因为那不完全是作者所询问的内容,我假设。 - Malcolm

13

== 在Java中比较对象(在这种情况下是字符串)的地址。

您需要使用parts[0].equals("231")


4
它比较物体的身份标识。这可能在内部实现为地址,但JVM规范和JLS在这里并未谈论地址。 - Joachim Sauer
是的,我也看到了。这只是一些小问题,但严格来说,你不能说它比较地址。(尽管如果存在任何未实现该方式的JVM,我会感到有点震惊...) - user435779

7

使用equals方法:parts[0].equals("231")。==运算符比较对象引用。


5
"

“==”比较对象引用,在您的情况下,“231”是与parts [0]不同的对象。

您需要使用String.equals

"
parts[0].equals("231")

5
使用"foo".equals(bar)比bar.equals("foo")更加明智。第一段代码无论bar是否为空都可以正常工作,而第二段代码将抛出NullPointerException异常。 - William Brendel

4
答案很简单:当你通过 == 操作符比较字符串时,实际上是在比较两个不同变量是否指向同一个字符串对象。但它们并不是,数组中的字符串和新创建的 "231" 是两个具有相同内容的不同字符串对象。
正确的做法是使用以下表达式:"231".equals(parts[0])"231".equalsIgnoreCase(parts[0])。这将给你所需的结果,并且如果这些字符串对象包含相同的值,则返回 true。

2
你也可以使用compareTo(String)方法:

compareTo(String)

String str = "test";

if( str.compareTo("test") == 0)
   //the argument string is equal to str;
else
   //the argument string is not equal to str;

1
它比equals()函数稍微贵一点,不太适用于比较字符串的相等性 - BalusC
谈到性能,我们必须提到hashCode和intern...此外,有一些例外情况,compareTo运行得更快。如果两个字符串具有相同的引用或它们具有不同的长度,则equals方法会提供更好的性能,但是引用检查和长度检查有时是多余的,例如比较子字符串是否相等。如果两个字符串没有相同的引用(用户输入,子字符串)并且具有相同的长度,则compereTo方法提供更好的性能。 - JCasso

2
我认为用测试案例来解释答案可能会更有帮助:
public class String231Test extends TestCase {
    private String  a;
    private String  b;

    protected void setUp() throws Exception {
        a = "231";
        StringBuffer sb = new StringBuffer();
        sb.append("231");
        b = sb.toString();
    }

    public void testEquals() throws Exception {
        assertTrue(a.equals(b));
    }

    public void testIdentity() throws Exception {
        assertFalse(a == b);
    }
}

1

这里有一个非常好的例子。在Java中,使用字符串的'=='运算符可能会非常棘手。

class Foo {
    public static void main(String[] args) {
        String a = "hello";
        String b = "hello";
        String c = "h";
        c = c + "ello";

        String operator = null;

        if(a == b) {
            operator = " == ";
        } else {
            operator = " != ";
        }

        System.out.println(a + operator + b);

        if(a == c) {
            operator = " == ";
        } else {
            operator = " != ";
        }

        System.out.println(a + operator + c);

        if(a == "hello") {
            operator = " == ";
        } else {
            operator = " != ";
        }

        System.out.println(a + operator + "hello");

        if(c == "hello") {
            operator = " == ";
        } else {
            operator = " != ";
        }

        System.out.println(c + operator + "hello");
    }
}

这将会产生以下输出:

hello == hello
hello != hello
hello == hello
hello != hello

1
实际上,无论在哪里直接使用文字 "hello",它都指向编译时创建的同一对象,称为内部化字符串,因此通过 == 进行引用相等性测试会通过,但 c 是在运行时组成的,并指向其他对象,因此它与任何 "hello" 文字面量不是引用相等的。 - kstep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接