Effective Java - 对所有对象都通用的方法

覆盖equals遵守通用约定

  • 自反性
  • 对称性
  • 传递性
  • 一致性
  • 非空性 非null引用值x,x.equals(null)返回false
  • 判断FloatDouble相等使用Float.compare或者Double.compare方法,因为存在Float.NaN/-0.0f以及类似的double常量

覆盖equals时总要覆盖hashCode

  • 相等的对象必须具有相等的散列码
  • 不相等的对象产生不相等的散列码
  • 覆盖equals方法不覆盖hashCode会导致:该类无法结合基于散列的所有集合(HashMap/HashSet/HashTable)正常工作

始终要覆盖toString

  • Object.toString方法包含类名+“@”+散列码的十六进制表示法
  • 建议所有的子类都覆盖这个方法
  • toString方法需要提供详细的注释或者说明意图
  • toString返回值中所有信息,每个都要提供访问的方法
  • toString在文档中指定返回值的格式(有哪些关键的字段),最好提供一个相匹配的静态工厂或者构造器(关键字段作为参数)。
    java平台类库中的BigInteger/BigDecimal和绝大多数的基本类型包装类都采取这种做法。

谨慎的覆盖clone

  • Cloneable接口没有任何方法,如果类实现了Caloneable接口Objectclone方法就会该类的逐域拷贝,否则抛出CloneNotSupportedException
  • 类每个域中包含一个基本类型的值或者一个指向不可变对象的引用,super.clone()返回即可

    不可变对象(Immutable Objects)即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变,反之即为可变对象(Mutable Objects)。
    不可变对象的类即为不可变类(Immutable Class)。Java平台类库中包含许多不可变类,如String、基本类型的包装类、BigInteger和BigDecimal等。

  • 类包含的域引用了可变对象仅仅使用super.clone可能会导致灾难性的后果
  • clone架构与引用可变对象的final域的正常用法不兼容
  • 其他拷贝的办法:拷贝构造器或者拷贝工厂,唯一参数类型是包含该构造器的类
    1
    2
    3
    4
    拷贝构造器:public Yum(Yum yum)
    拷贝静态工厂:public static Yum newInstatnce(Yum yum)
    参数类型可以是该类实现的接口(转换构造器或转换工厂)允许客户选择拷贝的实现类型。例如参数为接口Set,可以把一个HashSet转换为TreeSet
    专家级程序员干脆从来不去覆盖clone方法

考虑实现Comparable接口

  • compareTo并没有在object类中声明
  • 类实现了Comparable接口表明它的实例具有内在的排序关系
  • Java平台类库中所有的值类(value classes 实例表示一个值的类)都实现了Comparable接口
  • 自定义值类具有非常明显的内在排序关系需要实现这个接口
  • compareTo方法通常情况下返回结果应当和equals方法返回结果相同,即与equals一致(consistent with equals)。虽然绝非必要,但是违反此条件应当明确予以说明。
  • equals方法不一致(inconsistent with equals),违反约定仍能正常工作。集合接口是按equals方法定义通用约定,但有序集合是按compareTo方法定义通用约定。如果不一致可能实例在不同的集合中比较结果不相等。

    例如:new BigDecimal(“1.00”)与new BigDecimal(“1.0”)添加到HashSet中使用equals方法比较结果不想等。
    但在TreeSet中使用compareTo方法比较是相等的。