java代码优化——覆盖equals方法的通用约定

Object所有的非final方法都有明确的通用约定。本篇文章讲述覆盖equals方法的一些通用约定。覆盖equals方法看起来似乎很简单,但是有许多覆盖方式会导致错误。

不覆盖equals方法的情况
通常我们不必覆盖equals方法,而是沿用Object类为我们提供的实现:

public boolean equals(Object obj) {
  return (this == obj);
}

在这种情况下,类的每个实例只与它自己相等。

具体有以下情形可以不覆盖equals方法:

①类的每个实例本质上都是唯一的:例如Thread

②枚举类型:每个值最多只存在一个对象,不需要覆盖equals

③不关心是否提供了“逻辑相等”的测试功能

④超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的: Set->AbstractSet List->AbstractList Map->AbstractMap

⑤类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用

何时应覆盖equals方法

①类具有特有的逻辑相等概念

②超类没有覆盖equals以实现期望的行为

覆盖equals需要遵守的约定
为了保证类拥有正确的行为,我们必须遵守如下的约定(来自Object规范[JavaSE6])

自反性(reflexive):对于任何非null的引用值x,x.equals(x)必须返回true。

对称性(symmetric):对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(z)必须返回true。

传递性(transitive):对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。

一致性(consistent):对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false。

非空性(non-nullity):对于任何非null的引用值x,x.equals(null)必须返回false。

虽然这些规定看起来没什么特别,但一旦违反了它们,你的程序将会表现不正常,甚至崩溃,而且很难找到失败的根源。有许多类,包括所有的集合类在内,都依赖于传递给它们的对象是否遵守了equals约定。

实现高质量equals方法的诀窍
以下步骤一步步实现,即可完成高质量的equals方法覆盖。

使用==操作符检查“参数是否为这个对象的引用”。如果是,则返回true。这只不过是一种性能优化,以尽可能避免后面的比较。

使用instanceof操作符检查“参数是否为正确的类型”。如果不是,则返回false。

把参数转换成正确的类型

对于该类中的每个“关键(significant)”域,检查参数中的域是否与该对象中对应的域相匹配

编写完equals之后问自己:是否是对称的、传递的、一致的(自反性及非空性一般自行满足了)。

使用以上步骤实现的equals方法满足Java规范,可以很好地与其它类协作。(并不一定总是完全满足以上5个通用约定,需灵活考虑)

告诫
覆盖equals时总要覆盖hashCode
不要企图让equals方法过于智能。过度寻求等价关系很容易使自己陷入麻烦
不要将equals声明中的Object对象替换为其他的类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

princeAladdin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值