设为首页 加入收藏

TOP

Effective Java - 谨慎覆盖equals
2015-02-02 14:22:31 来源: 作者: 【 】 浏览:8
Tags:Effective Java 谨慎 覆盖 equals

平时很难遇到需要覆盖equals的情况。


什么时候不需要覆盖equals?


如果要问什么时候需要覆盖equals?
答案正好和之前的问题相反。
即,类需要一个自己特有的逻辑相等概念,而且超类提供的equals不满足自己的行为。
(PS:对于枚举而言,逻辑相等和对象相等都是一回事。)


既然只好覆盖equals,我们就需要遵守一些规定:


其实这些规定随便拿出一个都是很好理解的。
难点在于,当我遵守一个规定时有可能违反另一个规定


自反性就不用说了,很难想想会有人违反这一点。


关于对称性,下面提供一个反面例子:


这个例子显然违反对称性,即x.equals(y)为true 但 y.equals(x)为false。
不仅是在显示调用时,如果将这种类型作为泛型放到集合之类的地方,会发生难以预料的行为。


而对于上面这个例子,在equals方法中我就不牵扯其他类型,去掉String实例的判断就可以了。


关于传递性,即,当x.equals(y)为true 且 y.equals(z)为true 则 x.equals(z)为true。
这个规定在对类进行扩展时尤其明显。


比如,我用x,y描述某个Point:



现在我想给Point加点颜色:


似乎很自然的提供了ColorPoint的equals方法,但他连对称性的没能满足。

于是我们加以修改,令其满足对称性:



好了,接下来我们就该考虑传递性了。
比如我们现在有三个实例,1个Point和2个ColorPoint....
然后很显然,不满足<当x.equals(y)为true 且 y.equals(z)为true 则 x.equals(z)为true>。
事实上,我们无法在扩展可实例化类的同时,既增加新的值组件,又保留equals约定。


于是我索性不用instanceof,改用getClass()。
这个确实可以解决问题,但很难令人接受。
如果我有一个子类没有覆盖equals,此时equals的结果永远是false。


既然如此,我就放弃继承,改用复合(composition)。
以上面的ColorPoint作为例子,将Point变成ColorPoint的field,而不是去扩展。 代码如下:


关于一致性,即如果两者相等则始终相等,除非有一方被修改。
这一点与其说equals方法,到不如思考写一个类的时候,这个类应该设计成可变还是不可变。
如果是不可变的,则需要保证一致性。


考虑到这些规定,以下是重写equals时的一些建议:


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Effective Java - 避免使用finali.. 下一篇Effective Java - 谨慎覆盖clone

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: