【问题标题】:Is Java's assertEquals method reliable?Java 的 assertEquals 方法可靠吗?
【发布时间】:2019-04-04 02:25:05
【问题描述】:

我知道== 在比较两个Strings 时存在一些问题。似乎String.equals() 是一种更好的方法。好吧,我正在做 JUnit 测试,我倾向于使用 assertEquals(str1, str2)。这是断言两个字符串包含相同内容的可靠方法吗?我会使用assertTrue(str1.equals(str2)),但是您不会看到失败时的预期值和实际值是什么。

在相关说明中,是否有人提供指向明确解释str1 == str2 问题的页面或主题的链接?

【问题讨论】:

  • 如果您不确定,您可以阅读代码或 Javadoc。顺便说一句,如果你想测试它们是同一个对象,你可以使用 assertSame。
  • 如果 str1 和 str2 为 null,assertEquals() 为 true,但 assertTrue(str1.equals(str2)) 抛出异常。第一个示例还会打印一条有用的错误消息,例如 str1 和 str2 的内容,第二个不会。

标签: java string junit junit4


【解决方案1】:

在 Java 中比较 Strings 时,您应该始终使用 .equals()

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

所以,使用assertEquals(string1, string2) 绝对安全。 (因为Strings 是Objects)

Here is a link to a great Stackoverflow question 关于==.equals() 之间的一些差异。

【讨论】:

  • IIRC assertEquals() 如果两个字符串都为空,则成功。如果这不是你想要的,那么也调用 assertNotNull()。
  • 另外,如果你想测试 ==,你可以调用 assertSame()
  • 我不会说总是;有时需要引用相等,即使对于字符串也是如此。
【解决方案2】:

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

要了解为什么== 不应该与字符串一起使用,您需要了解== 的作用:它进行身份检查。也就是说,a == b 检查ab 是否引用相同的对象。它是语言中内置的,它的行为不能被不同的类改变。另一方面,equals 方法可以被类覆盖。虽然它的默认行为(在Object 类中)是使用== 运算符进行身份检查,但包括String 在内的许多类会覆盖它以进行“等效”检查。对于Stringab 不是检查是否指向同一个对象,而是检查它们引用的对象是否都是包含完全相同字符的字符串。

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

与字符串混淆的一点是,Java 有一个“实习”字符串的概念,并且(有效地)自动在代码中的任何字符串文字上执行。这意味着如果您的代码中有两个等效的字符串文字(即使它们在不同的类中),它们实际上都会引用同一个 String 对象。这使得== 运算符返回true 的频率超出了人们的预期。

【讨论】:

  • "也就是说,a == b 检查 a 和 b 是否是同一个对象。"从技术上讲,它检查 a 和 b 是否引用同一个对象,因为 a 和 b 是引用。除非我错了。
  • @user1903064 是正确的。由于非原始变量只能包含 Java 中的引用,因此在谈论它们时通常会跳过额外的间接级别,但我同意在这种情况下更明确是有益的。我已经更新了答案。感谢您的建议!
【解决方案3】:

简而言之 - 你可以有两个 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);
        }
    }
    

    【讨论】:

      【解决方案5】:

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

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

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

      【讨论】:

        【解决方案6】:

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

        还有assertSame(obj1, obj2) 可以执行obj1 == obj2(即验证obj1obj2 引用的是相同 实例),这是您要避免的。

        所以你很好。

        【讨论】:

          【解决方案7】:

          == 运算符检查两个Objects 是否完全相同Object。”

          http://leepoint.net/notes-java/data/strings/12stringcomparison.html

          String是java中的Object,所以属于比较规则的范畴。

          【讨论】:

          • 这没有回答问题,有点误导。您不能在字符串上可靠地执行 ==
          猜你喜欢
          • 2012-06-29
          • 2013-06-20
          • 1970-01-01
          • 2023-03-06
          • 2011-03-18
          • 2018-02-04
          • 1970-01-01
          • 1970-01-01
          • 2010-11-02
          相关资源
          最近更新 更多