最近在复习软件构造,学习到ADT和OOP的等价性这一部分,这一部分对于等价性提出了四个概念:引用等价性、对象等价性、观察等价性、行为等价性,单独看还是能理解,但回过头来一综合,还是有点懵,分不太清他们之间的联系,下面就来研究一下这四者之间的关系
1.引用等价性
引用等价性比较简单粗暴,只需考虑两个对象是否指向内存里的同一段空间,及内存地址是否相等。引用等价性也是“==”操作符、以及Object类实现的缺省的equals()方法的判断逻辑;
2. 对象等价性
对象等价性就是判断两个对象的内容是否相等,前面说过,Object类实现的缺省的equals()方法是基于引用等价性,但对于immutable数据类型,这显得太过死板了,所以通常需要重写equals()方法来判断两个不可变对象的内容是否相等;
如果说引用等价性和对象等价性是表层的区别,那么观察等价性和行为等价性就是更深层次的内容
3.观察等价性
观察等价性就是在不改变状态的前提下,两个mutable对象是否看起来一致。如果我们只从用户的角度去观察这两个对象而且不调用mutator方法时,它们之间所展现出的等价性就是观察等价性
4.行为等价性
行为等价性说的是,调用两个对象的任何方法(包括mutator),他们产生一致的结果,即“一致的行为”
通俗来说,对于mutable数据类型,两个对象的观察等价性是在某一个时刻看起来相等;而行为等价性是两个对象每时每刻都相等。由于mutable类型是可变的,要保证每时每刻都相等,只能令二者指向一个内存空间(即保证引用等价性)
需要注意的是,一般只针对mutable数据类型讨论观察等价性和行为等价性,而对于immutable数据类型,它的属性一般不允许改变(忽略有益的改变,不在讨论范围内),所以观察等价性和行为等价性的意义相同(可以简单理解为,观察等价性和行为等价性依靠调不调用mutator方法来区分,既然immutable类型都没有mutator方法,就无法区分它的观察等价性和行为等价性)
5.Java中观察等价性和行为等价性对编程的影响
对于mutable类型,Java往往实现严格的观察等价性,但可能会带来意想不到的问题
所以我们在自己编程时,尽量使用行为等价性(内存地址相同)判断,这也解释了mutable可变数据类型为什么不需要重写equals()和hashcode()方法
而对于immutable类型,它的观察等价性和行为等价性是一回事。那么,如果要判断两个immutable对象是否“看起来”一致,往往需要比较他们的内容(即内存地址不同的两个对象,他们的内容相同,也应该被判定为等价),所以在实现时需要重写equals()和hashcode()方法