等价性是基于等价关系的,满足自反、对称、传递三个性质,它的空间意义是:如果R中的多个值都对应于A中的同一个值,那么这些R值都应该是等价的。
1. 不可变类型的等价性
判断等价的两个方式:
- AF映射到同样的结果,则等价。
- 站在外部观察者角度:对两个对象调用任何相同的操作,都会得到相同的结果,则认为这两个对象是等价的。反之亦然。
两个等价的对象调用相同的Observer应该返回相同的结果。
等价性
== vs. equals()
- 引用等价性:使用==判断地址是否相同作为判断是否等价的依据。对基本数据类型,必须使用这种办法判断是否相等。
- 对象等价性:使用equals()方判断两个对象是否相同法作为判断是否等价的依据,对于对象类型,使用这种办法来判断对象是否等价,如果只用==则是在判断两个对象的ID(内存里的同一空间)是否相等。
equals()和hashCode()
在Object中,equals()的实现为==,而hashCode()的实现为返回内存地址。所以体验极差,需要重写。
重写Object中的equals()方法时要注意参数类型为Object,重写的时候要保持方法参数列表、可见性、返回值必须与父类一致。所以最好使用@Override声明。
equals()方法应该满足下面三个一条件:
- 等价关系:自反、传递、对称
- 除非对象被修改了,否则调用多次equals应同样的结果
- “相等”的对象,其hashCode()的结果必须一致
关于第3点,java在判断两个对象是否相等的时候,先去判断这两个对象的hashCode是否相等,如果不相等,则不会再去调用equals()方法,直接返回false不相等。所以等价的对象必须有相同的hashCode,而不相等的对象,也可以映射为同样的hashCode,但性能会变差。
所以,当实现equals()方法的时候,最好同时实现hashCode()方法,除非你能保证说设计的ADT不会被放入到hash类型的集合中,显然这不太现实。
2. 可变数据类型的等价性
等价性
-
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致。调用Observer方法表现出相同的结果。约等于对象等价性。
-
行为等价性:调用对象的任何方法都展示出一致的结果。包括mutator、producer、observer。约等于引用等价性。
equals()和hashCode()
所以,对可变类型,实现行为等价性即可,也就是说,只有指向同样内存空间的对象才是相等的。所以对可变类型来说,无需重写这两个函数,直接继承Object的equals()和hashCode()即可。