Java的assertEquals方法可靠吗?


199

我知道==比较两个时会有一些问题Strings。看来这String.equals()是一个更好的方法。好吧,我正在进行JUnit测试,而我倾向于使用assertEquals(str1, str2)。这是断言两个字符串包含相同内容的可靠方法吗?我会使用assertTrue(str1.equals(str2)),但是那样的话,您将无法获得预期的失败值和实际值。

在相关说明中,是否有人链接到页面或线程以清楚地解释问题所在str1 == str2


1
如果不确定,则可以阅读代码或Javadoc。顺便说一句,如果要测试它们是同一对象,则可以使用assertSame。
彼得·劳瑞

2
如果str1和str2为null,则assertEquals()为true,但是assertTrue(str1.equals(str2))引发异常。第一个示例还将打印一条有用的错误消息,例如str1和str2的内容,第二个示例则不会。
彼得·劳瑞

Answers:


274

在Java中进行比较时应始终使用。.equals()Strings

JUnit调用该.equals()方法以确定方法中的相等性assertEquals(Object o1, Object o2)

因此,您绝对可以放心使用assertEquals(string1, string2)。(因为Strings是Object

这是一个关于Stackoverflow问题的链接,该问题涉及==和之间的一些差异.equals()


12
如果两个字符串都为null,则IIRC assertEquals()成功。如果这不是您想要的,则也调用assertNotNull()。
finnw

10
此外,如果您要测试==,则可以调用assertSame()
詹姆斯

7
我不会总是说; 有时,即使对于字符串,也希望引用相等。
卡鲁2014年

30

assertEquals使用该equals方法进行比较。有一个不同的assert assertSame,它使用==运算符。

要了解为什么==不应该将字符串与字符串一起使用,您需要了解==它的作用:它将进行身份检查。也就是说,a == b检查是否ab同一个对象。它是语言的内置语言,其行为不能由不同的类更改。equals另一方面,该方法可以被类覆盖。尽管它的默认行为(在Object该类中)是使用==运算符进行身份检查,但许多类(包括)都对其进行了String覆盖,以进行“等效性”检查。在的情况下String,除了检查ab引用相同的对象外,a.equals(b) 检查它们所引用的对象是否都是包含完全相同字符的字符串。

比喻时间:想象每个String对象都是一张纸,上面写着一些东西。假设我有两张纸,上面写有“ Foo”,另一张纸上写有“ Bar”。如果我将前两张纸==用于比较,它将返回,false因为它本质上是在问“这些纸是同一张纸吗?”。它甚至不需要查看纸上写的内容。我给它两张纸(而不是同一张纸两次)的事实意味着它将会返回falseequals但是,如果我使用该equals方法,则该方法将读取两张纸,并看到它们说的是同一句话(“ Foo”),因此它将返回true

与String混淆的一点是Java具有“ interning”字符串的概念,并且(有效地)对代码中的任何字符串文字自动执行。这意味着,如果您的代码中有两个等效的字符串文字(即使它们位于不同的类中),则它们实际上都将引用同一String对象。这使==操作员返回的true次数比预期的要多。


“也就是说,a == b检查a和b是否是同一对象。” 从技术上讲,它检查a和b是否引用同一对象,因为a和b是引用。除非我很错。
鲍勃

@ user1903064是正确的。由于非基本变量只能包含Java中的引用,因此在谈论它们时通常会跳过额外的间接级别,但是我同意在这种情况下更明确是有益的。我已经更新了答案。谢谢你的建议!
劳伦斯·贡萨尔维斯

7

简而言之-您可以有两个String对象,这些对象包含相同的字符,但是是不同的对象(位于不同的内存位置)。==运算符将检查两个引用是否指向相同的对象(内存位置),但是equals()方法将检查字符是否相同。

通常,您有兴趣检查两个字符串是否包含相同的字符,而不是它们是否指向相同的存储位置。


4
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}

3

是的,它一直用于测试。测试框架很有可能使用.equals()进行此类比较。

以下是解释“字符串相等错误”的链接。本质上,Java中的字符串是对象,当您比较对象相等性时,通常根据内存地址而不是内容进行比较。因此,即使它们的内容相同,两个字符串也不会占用相同的地址,即使它们在打印时看起来相同,也不会正确匹配。

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/


3

JUnit assertEquals(obj1, obj2)确实会调用obj1.equals(obj2)

还有一种方法可以assertSame(obj1, obj2)做到obj1 == obj2(即验证obj1obj2引用同一实例),这就是您要避免的方法。

很好。


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.