Effective Java:Ch3_Methods:Item8_重写equals方法时遵循通用约定(五)

2014-11-24 11:59:54 · 作者: · 浏览: 135
可使用如下习惯用法来进行比较:
[java]
(field == null o.field == null : field.equals(o.field))
如果field和o.field总是相同的引用,则下面方法会更快:
[java]
(field == o.field || (field != null && field.equals(o.field)))
对于某些类,例如上面的CaseInsensitiveString,域的比较要比简单的相等性测试要复杂得多。如果是这种情况,你可能会希望保存该域的一个标准形式(canonical form),equals方法在这些标准形式上进行低开销的精确比较,而不是进行高开销的非精确比较。这种方式最适合于不可变类(Item15);如果对象改变,需要连带更新其标准形式。
域比较的顺序可能会影响equals方法的性能。为了获得最佳性能,应该首先比较哪些最可能不一致的域、开销最小的域。不应该比较哪些并非对象逻辑状态的域,例如同步操作的Lock域。不应该比较冗余域,这些域可通过关键域计算而得,但是这样做可能提高equals方法的性能。如果冗余域代表了对整个对象的综述,那么对比这些域就能够节省比较开销。【例】例如,假设有个Polygon类,并缓存了面积域,如果两个Polygon的面积不等,那就不用再去比较他们的边和顶点了。
5)当你完成equals方法后,问自己三个问题:它是否是对称的、传递的、一致的?并且不仅是自问,还要编写单元测试来检验这些特性。如果不通过,找出原因,据此来修改equals方法。当然,equals还需要满徐其他两个特性(自反性、非空性),不过这两种特性通常会自动满足。
Item9中的PhoneNumber.equals就是根据上述诀窍编写的。下面是最后的一些说明:
当重写equals时必须重写hashCode(Item9)
不要让equals过度聪明。如果只简单地测试域是否相等,则不难满足equals约定;而当过度地寻求等价关系,则容易陷入麻烦之中。例如File类不应该将指向同一文件的符号链接当做相等对象来看待。所幸File类没有这样做。
在equals方法声明中不要将Object替换为其他类型。为了防止这种情况,应该在每次重写equals时都是用@Override。