快速业务通道

Java:所有的equals方法实现都是错误的? - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-21

Java:所有的equals方法实现都是错误的?

时间:2011-01-05 司马牵牛译

本文介绍了一种改写(override)equals 方法的技巧。使用该技巧,即使在实体类的子类添加了新的域(field)时,仍然能够满足 equals 方法的约定。

在《Effective Java》一书的第 8 条目中,Josh Bloch 将子类化时满足 equals 约定这一困难描述为:面向对象语言中等值关系的最根本问题。Bloch 这样写道:

不存在一种方式,能够在扩展非实例类并添加值组件的同时,仍然满足equals的约定。除非你愿意放弃面向对象的抽象性这一优点。

《Programming in Scala》一书中的第 28 章提供了一种方法,子类可以对非实例类进行扩展,添加值组件,而同时满足 equals 约定。虽然书中提供的那种技巧是用于定义 Scala 类,但一样适用于 Java 中的 类定义。在本文中,为了讲解这种方法,我将使用《Programming in Scala》中相关章节,改编相关的文本,并将原书中的 Scala 示例代码转换为了 Java 代码。

常见的等值陷阱

Class java.lang.Object 定义了一个 equals 方法,其中的子类可以进行改写(override)。不幸的是,最终的结果表明,在面向对象语言中,编写正确的等值方法相当困难。事实上,在对 Java 代码的大量正文进行研究之后,几位作者在 2007 年的一份论文中作出如下结论:几乎所有 equals 方法的实现都是错误的。

这是一个严重的问题,因为等值方法是很多代码的根本。其一,对于类型 C,一个错误的等值方法可能意味着,你不能可靠地将一个类型 C 的对象放入集合中。你可能有两个等值的类型 C 元素 elem1、elem2,即“em1.equals(elem2)”输出 true。然而,在下面的示例中,equals 方法的实现就是一种常见的错误:

Set< C> hashSet = new java.util.HashSet< C>(); hashSet.add(elem1); hashSet.contains(elem2); // 返回 false!

存在四种常见的陷阱,它们都会在改写equals时导致非一致性的行为:

◆使用错误的原型对equals进行定义。

◆更改equals而未同时更改 hashCode。

◆对equals进行定义时涉及可变域(field)。

◆未能成功地将equals定义为等值关系。

这四种陷阱将在下文中具体讲述。

陷阱 1:使用错误的原型对equals进行定义

在下面的代码中,我们将为普通点的类添加一个等值方法:

public class Point {   private final int x;   private final int y;   public Point(int x, int y) {   this.x = x;   this.y = y;   }   public int getX() {   return x;   }   public int getY() {   return y;   }   // ... }

Java:所有的equals方法实现都是错误的?(2)

时间:2011-01-05 司马牵牛译

一个显而易见的错误定义如下:

// 一个完全错误的 equals 定义   public boolean equals(Point other) {   return (this.getX() == other.getX() && this.getY() == other.getY()); }

这种方法的错误之处是什么?初一看,它可以正常运行:

Point p1 = new Point(1, 2); Point p2 = new Point(1, 2); Point q = new Point(2, 3); System.out.println(p1.equals(p2)); // prints true System.out.println(p1.equals(q)); // 输出 false

然而,一旦你将point放入集合中,问题就出来了:

import java.util.HashSet; HashSet< Point> coll = new HashSet< Point>(); coll.add(p1); System.out.println(coll.contains(p2)); // 输出 false

coll 怎么可能不包含 p2 呢?你已经将 p1 添加到其中,而 p1 等于 p2。在下面的互操作中,进行比较的点的具体类型被隐藏,这时,导致问题的原

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号