在Java等于方法中进行精确比较

多年来,我一直在处理旧版Java代码,因此遇到了微妙的逻辑和性能问题,这些问题可以追溯到不正确覆盖的Object.equals(Object)方法。 尽管“等于”方法背后的概念看似简单,但Josh Bloch在《 有效Java》中指出:“重写equals方法似乎很简单,但是有很多方法可以弄错它,其后果可能是可怕的。 避免问题的最简单方法是不重写equals方法,在这种情况下,每个实例仅等于其自身。” 在这篇文章中,我看了一种使equals(Object)错误的“许多方法”之一:无法完全比较被评估是否相等的两个对象的完全相同的特征。

下一个代码清单是针对MismatchedFieldAccessor类的。 此类的equals(Object)方法有缺陷,因为它将类的直接属性someString与从另一个对象的getSomeString()检索的值进行比较。 在大多数Java类中,将类的字段与其访问器/获取方法进行比较将可以正常工作,因为访问器/获取方法仅返回相关的字段。 但是,在此示例类中,accessor / get方法的作用不只是简单地返回该字段,而且还使该字段与equals(Object)方法中的get / accessor方法的比较不一致。 (请注意,此处不建议使用“ get”方法来执行此类操作,只是作为一个易于理解的示例而存在。)

package dustin.examples.brokenequals;

import java.util.Objects;

/**
 * Demonstrate problem with mismatched field/accessor in
 * overridden equals(Object) implementation.
 */
public final class MismatchedFieldAccessor
{
   private final String someString;

   public MismatchedFieldAccessor(final String newString)
   {
      someString = newString;
   }

   public String getSomeString()
   {
      return someString != null ? someString : "";
   }

   @Override
   public boolean equals(final Object other)
   {
      if (this == other)
      {
         return true;
      }
      if (other == null || getClass() != other.getClass())
      {
         return false;
      }

      final MismatchedFieldAccessor that = (MismatchedFieldAccessor) other;

      return Objects.equals(this.someString, that.getSomeString());
   }

   @Override
   public int hashCode()
   {
      return someString != null ? someString.hashCode() : 0;
   }
}

如果使用适当的单元测试进行测试,上述类将失败。 下一个代码清单中列出的两个单元测试指出了类的equals方法的问题。

public void testEqualsOnConstructedWithNull()
{
   final MismatchedFieldAccessor accessor = new MismatchedFieldAccessor(null);
   Assert.assertEquals(null, accessor.getSomeString());
}

@Test
public void testEqualsWithEqualsVerifier()
{
   EqualsVerifier.forClass(MismatchedFieldAccessor.class).verify();
}

上面显示的第一个单元测试失败,并显示以下消息:

java.lang.AssertionError: 
Expected :null
Actual   :

第二个单元测试利用方便的EqualsVerifier库来确定此equals(Object)实现的问题(已添加重点 ):

java.lang.AssertionError: Reflexivity: object does not equal an identical copy of itself:
  dustin.examples.brokenequals.MismatchedFieldAccessor@0
If this is intentional, consider suppressing Warning.IDENTICAL_COPY
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages

 at nl.jqno.equalsverifier.EqualsVerifier.handleError(EqualsVerifier.java:381)
 at nl.jqno.equalsverifier.EqualsVerifier.verify(EqualsVerifier.java:367)
 at dustin.examples.brokenequals.MismatchedFieldAccessorTest.testEqualsWithEqualsVerifier(MismatchedFieldAccessorTest.java:36)

如果不认真执行,检查和测试, equals方法可能会变坏,这是许多方法之一。 幸运的是,解决此特定问题的方法很容易:始终将要比较的两个实例的相同字段或相同方法的返回对象进行比较,以确保相等。 在本文中使用的示例中,直接比较两个“ someString”字段将使“ equals”方法正常工作。

翻译自: https://www.javacodegeeks.com/2016/12/compare-exactly-java-equals-methods.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值