第八讲 数据结构实例的等价性
8.1 等价关系的性质
自反、对称、传递
8.2 不可变数据结构的等价
对象等价性:AF映射到相同的结果即等价。
在外部,对两个对象调用相同的操作,结果都一样。
- 引用等价性:使用==来判断是不是同一个引用。
- 对象等价性:使用equals来判断。
8.3 可变数据结构的等价
- 观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致。(内容是否一致)
- 行为等价性:调用对象的任何方法都展示出一致的结果。(一般方法,引用等价,直接继承Object)
当可变数据类型被放到Hash集合类中时,Hash类的equals不确定是不是真的。
有可能两个相等集合类进行比较是真的,变更一个之后,还是真的。
所以对可变类型来说,无需重写equals和hashCode,直接继承Object的两个方法即可。
如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。
常见的可变数据类型的等价性
Date: 观察等价性,判断getTime的值是否相等。
集合类:观察等价性,比较每一个元素是否equals另一个集合类中的对应元素。
StringBuilder:行为等价性,继承自Object。
8.4 重写equals方法
在Object中,equals实现的是引用等价性,为了满足期望的结果一般需要重写。
值得注意的是,其第一个参数类型应该是Object,如果是其他的就是重载了。
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VoteItem<?> other = (VoteItem<?>) obj;
return Objects.equals(candidate, other.candidate) && Objects.equals(value, other.value);
}
- 还可以使用instanceof
8.5 重写hashCode方法
等价的对象,其hashCode()的结果必须一致。
因此一个类的equals和hashCode必须同时被重写。
@Override
public int hashCode() {
int result = 17; // Nonzero is good
result = 31 * result + areaCode; // Constant must be odd
result = 31 * result + prefix; // " " " "
result = 31 * result + lineNumber; // " " " "
return result;
}
@Override
public int hashCode() {
short[] hashArray = {areaCode, prefix, lineNumber};
return Arrays.hashCode(hashArray);
}
@Override
public int hashCode() {
return Objects.hash(candidate, value);
}