ADT和OOP中的等价性
前言
等价性的划分:
不可变对象的引用等价性==和对象等价性equals()
可变对象的观察等价性和行为等价性
引用等价性
== 操作符比较引用。
它测试引用相等。两个引用是 == 如果它们指向内存中的相同存储。在快照图中,如果两个引用的箭头指向同一个对象气泡,则它们为==。
== 对基本数据类型,使用== 判定相等
对象等价性
equals()函数
equals()操作比较对象内容——换句话说,对象相等。
对对象类型,使用equals()
正常的equals()方法:在Object 中实现的缺省equals() 是在判断引用等价性,所以应该重写equals()方法
错误重写:这是Overload,不是重写
正确重写:
一个更好的方法去实现equals()
hashcode()函数
等价的对象必须有相同的hashCode
根据上面描述的Duration类,在修改equals()函数之后,d1.equals(d2)=true,但是输出hashCode()的值发现两者的哈希值不同
修改方法:为对象的每个组件计算一个散列代码,用于确定是否相等(通常通过调用每个组件的hashCode方法),然后组合这些散列代码,并进行一些算术操作。
对于Duration,这很容易,因为类的抽象值已经是一个整数值:
观察等价性
当不能通过不改变对象状态的观察来区分它们时,也就是说,只调用observer、producer和creator方法。这通常被严格地称为观察等价性,因为它测试两个对象在程序的当前状态下是否“看起来”相同。
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致
对可变类型来说,往往倾向于实现严格的观察等价性
实现观察等价性的缺陷:
行为等价性
当它们不能通过任何观察来区分时,甚至状态也会改变。这种解释允许调用两个对象上的任何方法,包括mutators。这被称为行为平等,因为它测试两个物体在当前状态和所有未来状态下是否会“表现”相同。
行为等价性:调用对象的任何方法都展示出一致的结果
对可变类型,实现行为等价性即可。也就是说,只有指向同样内存空间的objects,才是相等的。所以对可变类型来说,无需重写equals() and hashCode()这两个函数,直接继承Object 的两个方法即可。如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。
总结
1.对于不可变对象:
equals()应该比较抽象值。这就相当于说equals()应该提供行为平等。
hashCode()应该将抽象值映射为整数。
所以,不可变类型必须重写equals()和hashcode()函数
2.对于可变对象:
equals()应该比较引用,就像==一样。同样,这就相当于说equals()应该提供行为平等。
hashCode()应该将引用映射为一个整数。
所以,可变类型不需要重写equals()和hashcode()函数