您的位置:首页 > 其它

第八条:覆盖equals时请遵守通用约定

2016-04-21 11:05 162 查看
覆盖equals方法可能会导致错误,避免这类问题就是不覆盖equals方法,这样情况下,类的每个实例都与它自身相等。满足以下任何一个条件,都是期望的结果:

类的每个实例本质上都是唯一的

不关心类是否提供了“逻辑相等(logical equality)”的测试功能

超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的

类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用。在这种情况下,无疑是应该覆盖equals方法的,以防它被意外调用

 如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法。这通常是“值类”的情形,例如Integer或者Date。

 用equals方法比较值对象的引用时,我们希望知道它们在逻辑上是否相等,不想了解它们是否指向同一个对象,这就需要覆盖equals方法,这样也会使得这个类的实例可以被用作映射表(map)的键,或者集合(set)的元素。

自反性(reflexive)。对于任何非null的引用值x,x.equals(x)必须返回true。

对称性(symmetric)。对于任何非null的引用值x和y,当且仅当y.equal(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。

  没有哪个类是孤立的,一个类的实例通常会被频繁地传递给另一个类的实例,有许多类,包括所有的集合类在内,都依赖于传递给它们的对象是否遵守了equals约定。

自反性(reflexivity):仅仅说明对象必须等于其自身,违背这一条,把该类实例添加到集合中,contains方法返回false。

对称性(symmetry):任何两个对象对于“它们是否相等”的问题都必须保持一致。

传递性(transitivity):如果一个对象等于第二个对象,并且第二个对象又等于第三个对象,则第一个对象一定等于第三个对象。

注意:等价关系可能存在一个基本问题:无法在扩展可实例化的类的同时,即增加新的组件,同时又保留equals约定,除非愿意放弃面向对象的抽象所带来的优势。可以采用复合的形式。

一致性(consistency):如果两个对象相等,他们就必须始终保持相等,除非他们被修改了。

非空性(Non-nullity):所有对象必须不等于null。

结合所有这些要求,得出以下实现高质量的equals方法的诀窍:

使用==操作符检查“参数是否为这个对象的引用”

使用instanceof操作检查“参数是否为正确类型”。“正确类型”指equals方法所在的那个类,有些时候值该类所实现的某个接口。

把参数转换成正确的类型

对于该类中的每个“关键(significant)”域,检查参数中的域是否与该对象中对应的域相匹配。对于既不是float也不是double类型的基本数据,可以使用 == 操作符比较;对于对象引用域,可以递归地调用equals方法;对于double域,则使用Double.compare;对于float域,则使用Float.compare方法。有些对象引用域包含null可能是合法的,为了避免可能导致NullPointException异常,则可以使用下面的习惯语法来比较这样的域:



(filed == null ? obj.filed == null : filed.equals(obj.filed))


如果field和o.filed通常是相同的对象引用,可以这么做:

(filed == obj.filed || (filed != null && filed.equals(obj.filed)))


5. 当编写完equals方法之后,应该注意三个问题:它是否对称的、传递的、一致的?

其他

覆盖equals时总要覆盖hashCode

不要企图让equals方法过于智能

不要将equals声明中的Object对象替换为其他的类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: