Java中的相等——软件构造

1.什么是相等
在现实世界中,很多看似一样的物体,其实也并不相等。正如“没有两片完全相同的树叶”,从这个角度看,那么没有什么事完全相等的。

但是在工程应用方面,我们可以将很多模型抽象出来,只取其主要的特征,那么就有很多东西是完全相等的。同时,我们也有很多角度来判定两个物体是否是相等的。

从抽象函数角度来考虑,抽象函数是描述从R到A的映射关系的函数,即如何将表示空间中的一个值解释为抽象空间中的一个值。(AF: R → A ),它将具体的表示数据映射到了抽象的值。因此如果AF(a)=AF(b),我们就说a和b相等。

从数学角度思考,相等可以理解为“等价关系”。
设 R 是集合 A 上的一个二元关系,若R满足:
自反性:∀ a ∈A, => (a, a) ∈ R
对称性:(a, b) ∈R∧ a ≠ b => (b, a)∈R
传递性:(a, b)∈R,(b, c)∈R =>(a, c)∈R
则称R是定义在A上的一个等价关系。

以上两种角度其实是一样的,通过等价关系我们可以构建抽象函数;而抽象函数也能推出等价关系。

第三种判定抽象值相等的方法是从使用者或是外部的角度去观察。如果使用者从任何角度都无法观察到两个对象有任何不同,即每一个观察总会都会得到相同的结果。那么我们就可以判定这两个对象是相等的。

2.一些例子

public class Duration {
    private final int mins;
    private final int secs;
    // Rep invariant:
    //    mins >= 0, secs >= 0
    // Abstraction function:
    //    AF(min, secs) = the span of time of mins minutes and secs seconds

    /** Make a duration lasting for m minutes and s seconds. */
    public Duration(int m, int s) {
        mins = m; secs = s;
    }
    /** @return length of this duration in seconds */
    public long getLength() {
        return mins*60 + secs;
    }
}

在上面的例子中,用户输入分钟和秒,通过getLength函数可以将它们转换为总共的秒数。那么下面的四个对象,哪些是等价的。

Duration d1 = new Duration (1, 2);
Duration d2 = new Duration (1, 3);
Duration d3 = new Duration (0, 62);
Duration d4 = new Duration (1, 2);

显然,无论是从抽象函数,等价关系还是使用者角度来看,d1,d3,d4都是相等的。

3.在java中
在Java中判定相等常常关系到两个函数:equals()和hashCode()

我们定义两种相等:观察相等和行为相等。

观察相等:两个索引在不改变各自对象状态的前提下不能被区分。例如,只调用观察者、生产者、创建者。它测试的是这两个索引在当前程序状态下“看起来”相等。

行为相等:两个所以在任何代码的情况下都不能被区分,即使有一个对象调用了改造者。它测试的是两个对象是否会在未来所有的状态下“行为”相等。

对于不可变对象,观察相等和行为相等是完全等价的,因为它们没有改造者改变对象内部的状态。

对于可变对象,Java通常实现的是观察相等。例如两个不同的 List 对象包含相同的序列元素,那么equals() 操作就会返回真。但是使用观察相等会带来隐秘的bug,并且也会让我们很容易的破坏聚合类型的表示不变量。因此,可变类型的equals()应该实现为行为相等。

4.总结:

对于不可变类型:
equals() 应该比较抽象值是否相等。这和 equals() 比较行为相等性是一样的。
hashCode() 应该将抽象值映射为整数。
所以不可变类型应该同时覆盖 equals() 和 hashCode().

对于可变类型:
equals() 应该比较索引,就像"=="一样。同样的,这也是比较行为相等性。
hashCode() 应该将索引映射为整数。
所以可变类型不应该将 equals() 和 hashCode() 覆盖,而是直接继承 Object中的方法。

本文内容参考了来自MIT_6.031_sp18: Software Construction课程的Readings部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值