在学Java的同时,课下在看《Effective Java(中文版)》,虽然不能全部理解,但是感觉此书写的非常平直易读,遂做对基础学习部分做笔记。

在覆盖equals方法的时候,必须要遵守它的通用约定。下面是约定的内容,来自Object的规范。
  equals方法实现了等价关系(equivalence relation)其属性如下:

  •   自反性( flexive)对于任何非null的引用值x,x.equals(x)必须返回true
  •   对称性( symmetrIc):对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true.
  •   传递性( transitive):对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true.
  •   一致性( consistent):对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false.
  •   对于任何非null的引用值x,x.equals(null)必须返回false。

除非你对数学特别感兴趣,否则这些规定看起来可能有点让人感到恐惧,但是绝对不要忽视这些规定!如果违反了,就会发现程序将会表现得不正常,甚至崩溃,而且很难找到失败的根源。用 John Donne的话说,没有哪个类是孤立的。一个类的实例通常会被频繁地传递给另一个类的实例。有许多类,包括所有的集合类( collection class在内,都依赖于传递给它们的对象是否遵守了equals约定。

实现高质量equals的诀窍:

1.使用==操作符检查“参数是否为这个对象的引用”。如果是,则返回true。这只不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。
2.使用instanceof操作符检查“参数是否为正确的类型”。如果不是,则返回false。一般说来,所谓“正确的类型”是指equals方法所在的那个类。某些情况下,是指该类所实现的某个接口。如果类实现的接口改进了equals约定,允许在实现了该接口的类之间进行比较,那么就使用接口。集合接口如Set、List、Map和Map.Entry具有这样的特性。
3.把参数转换成正确的类型。因为转换之前进行过 instanceof测试,所以确保会成功。
4.对于该类中的每个“关键”(significant)域,检查参数中的域是否与该对象中对应的域相匹配。如果这些测试全部成功,则返回true;否则返回fase。如果第2步中的类型是个接口,就必须通过接口方法访问参数中的域;如果该类型是个类,也许就能够直接访问参数中的域,这要取决于它们的可访问性。

重写(覆盖)equals的一些告诫:
1.覆盖equals时总要覆盖hashCode。
2.不要企图让equals方法过于智能。
3.不要将equals声明中的Object对象替换为其他的类型。
以上为重写equals规约笔记。