第3章 对所有对象都通用的方法
10,重写 equals 时请遵守通用规定
10.1 在以下情况,类的每个实例都与它自身相等,不重写 equals 方法
- 类的每个实例都是唯一的。
- 类没有提供逻辑相等的测试功能。
- 超类已经重写了 equals 。超类的行为对于这个类也是合适的。
- 类是私有的,或者是包级私有的,可以确定它的 equals 方法永远不会被调用。
10.2 equals 通用约定
- 自反性
- 对称性
- 传递性
- 一致性
- 非空性:对于任何非null的引用值x,x.equals(null) 必须返回false
10.3 实现高质量 equals 方法的诀窍
- 使用 == 操作符检查“参数是否为这个对象的引用”。
- 使用 instanceof 操作符检查 “ 参数是否为正确的类型 ” 。
- 把参数转换为正确的类型。
- 对于该类中的每个关键(significant)域,检查参数中的域是否与对象中对应的域匹配。
10.4 告诫
- 重写 equals 总要重写 hashCode
- 不要让 equals 方法过于智能
- 不要将 equals 声明中的 Object 对象替换为其他的类型
10.5 Google开源的 AutoValue 框架自动重写 equals 方法
11,覆盖 equals 时总要覆盖 hashCode
-
在每个重写的 equals 的类中,都必须重写 hashCode 方法
-
不要试图从散列码计算中排除一个对象的关键域来提高性能
-
不要对 hashCode 方法的返回值做出具体的规定,因此客户端无法理所当然的依赖它;这样可以为修改提供灵活性
12,始终要重写toString
能重写就一定要重写
13,谨慎的重写clone
-
Object 中 clone 方法是受保护的。
-
反射调用也可能会失败,因为不能保证该对象一定具有可以访问的 clone 方法。
-
不可变的类永远都不应该提供 clone 方法。
-
实际上,clone 方法就是另一个构造器;必须确保它不会伤害到原有对象,并确保正确的创建被克隆对象中的约束条件。
-
为了使 Stack 类中的 clone 方法正常工作,它必须要拷贝栈的内部信息。最容易的做法是,在 elements 数组中递归调用clone
-
cloneable 架构与引用可变对象的 final 域的正确用法是不兼容的
-
对象拷贝的更好方法是提供一个拷贝构造器或者拷贝工厂
优势:
- 它们不依赖于某一种很有风险,语言之外的对象创建机制;
- 它们不要遵守尚未制定好文档的规范;
- 它们不会与final域的正常使用发生冲突
- 它们不会抛出不必要的受检异常
- 它们不需要进行类型转换
- 它们可以携带一个参数,参数类型是该类所实现的接口
14,考虑实现 Comparable 接口
-
compareTo 方法的通用约定与 equals 方法约定类似。
例外:
BigDecimal(1.0) .equals(BigDecimal(1.00)) = false
BigDecimal(1.0) .comparedTo(BigDecimal(1.00)) = true
-
比较后返回负整数,零,正整数或者抛出 ClassCastException 异常。
-
compareTo 不能跨类型比较,会抛出 ClassCastException 异常。
-
Comparable 接口是参数化的,而且compaeTo 方法是静态类型,因此不必进行类型检查,也不必进行参数类型转换。
-
compaeTo 方法中域的比较是顺序的比较,而不是同性的比较。
-
compaeTo 方法中使用关系操作符 < 和 > 是比较繁琐的并且容易出错,不再建议使用。