java代码优化equal_优化java代码的一些小技巧(三)————重写equals()方法

3.重新定义类里面的equals()方法

对象识别可能是一个很难解决的问题:

如果两个对象在内存中占据相同的位置,那么它们是相同的吗?

如果它们的id相同,它们是相同的吗?

或者如果所有的字段都相等呢?

虽然每个类都有自己的标识逻辑,但是在系统中有很多地方都需要去判断是否相等。例如,有如下的一个类,表示订单购买…

public class Purchase {

private long id;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

}

代码中肯定有很多地方都是类似下面这样写法:

Purchase originalPurchase = new Purchase();

Purchase updatedPurchase = new Purchase();

if (originalPurchase.getId() == updatedPurchase.getId()) {

// Execute some logic for equal purchases

}

这些逻辑调用的越多(反过来,违背了DRY原则:不做重复的事(Don't Repeat Yourself)),Purchase类的身份信息也会变得越来越多。

如果出于某种原因,更改了Purchase类的身份逻辑(例如,更改了标识符的类型),则需要更新标识逻辑所在的位置肯定也非常多。

我们应该在类的内部初始化这个逻辑,而不是通过系统将Purchase类的身份逻辑进行过多的传播。乍一看,我们可以创建一个新的方法,比如isSame,这个方法的入参是一个Purchase对象,并对每个对象的id进行比较,看看它们是否相同:

public class Purchase {

private long id;

public boolean isSame(Purchase other) {

return getId() == other.gerId();

}

}

虽然这是一个有效的解决方案,但是忽略了Java对象Object自有的方法——equals方法。Java中的每个类都是继承了Object类,虽然是隐式的,因此同样也就继承了equals方法。默认情况下,此方法将检查对象标识(内存中相同的对象),如JDK中的对象类定义(version 1.8.0_131)中的以下代码片段所示:

public boolean equals(Object obj) {

return (this == obj);

}

以下这个equals方法充当了注入身份逻辑的自然位置(通过重写默认的equals实现):

public class Purchase {

private long id;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

@Override

public boolean equals(Object other) {

if (this == other) {

return true;

}

else if (!(other instanceof Purchase)) {

return false;

}

else {

return ((Purchase) other).getId() == getId();

}

}

}

虽然这个equals方法看起来很复杂,但由于equals方法只接受类型对象的参数,所以我们只需要考虑三个案例:

另一个对象是当前对象(即originalPurchase.equals(originalPurchase)),根据定义,它们是同一个对象,因此返回true

另一个对象不是Purchase对象,在这种情况下,我们无法比较Purchase的id,因此,这两个对象不相等

其他对象不是同一个对象,但却是Purchase的实例,因此,是否相等取决于当前Purchase的id和其他Purchase是否相等

现在可以重构我们之前的条件,如下:

Purchase originalPurchase = new Purchase();

Purchase updatedPurchase = new Purchase();

if (originalPurchase.equals(updatedPurchase)) {

// Execute some logic for equal purchases

}

除了可以在系统中减少复制,重构默认的equals方法还有一些其它的优势。

例如,如果构造一个Purchase对象列表,并检查列表是否包含具有相同ID(内存中不同对象)的另一个Purchase对象,那么我们就会得到true值,因为这两个值被认为是相等的:

List purchases = new ArrayList<>();

purchases.add(originalPurchase);

purchases.contains(updatedPurchase); // True

通常,无论在什么地方,如果需要判断两个类是否相等,则只需要使用重写过的equals方法就可以了。如果希望使用由于继承了Object对象而隐式具有的equals方法去判断相等性,我们还可以使用= =操作符,如下:

if (originalPurchase == updatedPurchase) {

// The two objects are the same objects in memory

}

还需要注意的是,当equals方法被重写以后,hashCode方法也应该被重写。有关这两种方法之间关系的更多信息,以及如何正确定义hashCode方法,请自行检索。

重写equals方法不仅可以将身份逻辑在类的内部进行初始化,并在整个系统中减少了这种逻辑的扩散,它还允许Java语言对类做出有根据的决定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值