优化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<Purchase> 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语言对类做出有根据的决定。 

转载于:https://my.oschina.net/fl128818/blog/1550492

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值