所有对象都通用的方法
§ 重写 equals 时请遵守通用约定
什么时候应该重写 Object.equals?
如果类具有自己特有的 “逻辑相等” 概念,父类还没有重写过 equals 以实现期望的行为,这时我们需要重写 equals 方法,这通常属于 “值类” 的情形。
值类是仅仅一个表示值的类,例如 Integer
。或者自己定义的 DTO 类。
重写 equals 方法的通用约定:
- 自反性。对于任何非 null 的引用 x,x.equals(x) 必须返回 true
- 对称性。对于任何非 null 的引用 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 必须返回 true
- 传递性。对于任何非 null 的引用 x、y、z,如果 x.equals(y) 返回 true,并且 y.equals(z) 也返回 true,那么 x.equals(z) 也必须返回true
- 一致性。对于任何非 null 的引用 x 和 y,多次调用 x.equals(y) 会一致返回 true 或 false
- 对于任何非 null 的引用 x,x.equals(null) 必须返回 false。
同时还有最重要的提醒:
- 重写 equals 时总要重写 hashCode
- 不要试图让 equals 方法过于智能
- 不要将 equals 声明中的 Object 对象替换为其他类型。
1 | // 这是错误的,没有使用 Object 变成了重载,而不是重写 |
§ 重写 equals 时总要重写 hashCode
如果不这样做会违反 Object.hashCode 通用约定,导致该类无法结合所有基于散列的集合一起正常运作,包括 HashMap
、HashSet
等。
相等的对象必须具有相等的 散列码(hash code)
§ 始终要重写 toString
toString 通用约定指出,返回的字符串应该是:简洁的,信息丰富,且易于阅读的表达形式
§ 谨慎的重写 clone
§ 考虑实现 Comparable 接口
一旦类实现了 Comparable
接口,它就可以跟许多泛型算法以及依赖于该接口的集合实现进行协作,付出很小的努力就可以获得非常强大的功能。
Java 平台中所有的值类都实现了 Comparable
接口。如果你正在编写一个值类,具有非常明显的内在排序关系,那么应该坚决考虑实现这个接口:
1 | public interface Comparable<T> { |
compareTo 方法的通用约定与 equals 方法的相似。