快速业务通道

如何在Java中避免equals方法的隐藏陷阱 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-21
下,p1一定是在另外一个桶中,因此,p2永远找不到p1进行匹配。当然p2和p2也可能偶尔会被放入到一个桶中,在这种情况下,contains的结果就为true了。

最新一个Point类实现的问题是,它的实现违背了作为Object类的定义的hashCode的语义。

如果两个对象根据equals(Object)方法是相等的,那么在这两个对象上调用hashCode方法应该产生同样的值

事实上,在Java中,hashCode和equals需要一起被重定义是众所周知的。此外,hashCode只可以依赖于equals依赖的域来产生值。对于Point这个类来说,下面的的hashCode定义是一个非常合适的定义。

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; } @Override public boolean equals(Object other) { boolean result = false; if (other instanceof Point) { Point that = (Point) other; result = (this.getX() == that.getX() && this.getY() == that.getY()); } return result; } @Override public int hashCode() { return (41 * (41 + getX()) + getY()); } }

这只是hashCode一个可能的实现。x域加上常量41后的结果再乘与41并将结果在加上y域的值。这样做就可以以低成本的运行时间和低成本代码大小得到一个哈希码的合理的分布(译者注:性价比相对较高的做法)。

增加hashCode方法重载修正了定义类似Point类等价性的问题。然而,关于类的等价性仍然有其他的问题点待发现。

陷阱3:建立在会变化字段上的equals定义

让我们在Point类做一个非常微小的变化

public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void setX(int x) { // Problematic this.x = x; } public void setY(int y) { this.y = y; } @Override public boolean equals(Object other) { boolean result = false; if (other instanceof Point) { Point that = (Point) other; result = (this.getX() == that.getX() && this.getY() == that.getY()); } return result; } @Override public int hashCode() { return (41 * (41 + getX()) + getY()); } }

如何在Java中避免equals方法的隐藏陷阱(4)

时间:2011-01-04 blogjava 赵锟译

唯一的不同是x和y域不再是final,并且两个set方法被增加到类中来,并允许客户改变x和y的值。equals和hashCode这个方法的定义现在是基于在这两个会发生变化的域上,因此当他们的域的值改变时,结果也就跟着改变。因此一旦你将这个point对象放入到集合中你将会看到非常神奇的效果。

Point p = new Point(1, 2); HashSet<Point> coll = new HashSet<Point>(); coll.add(p); System.out.println(coll.contains(p)); // 打印 true

现在如果你改变p中的一个域,这个集合中还会包含point吗,我们将拭目以待。

p.setX(p.getX() + 1);

System.out.println(coll.contains(p)); // (有可能)打印 false

看起来非常的奇怪。p去那里去了?如果你通过集合的迭代器来检查p是否包含,你将会得到更奇怪的结果。

Iterator<Point> it = coll.iterator(); boolean containedP = false; while (it.hasNext()) { Point nextP = it.next(); if (nextP.equals(p)) { containedP = true; break; } } System.out.println(containedP); // 打印 true

结果是,集合中不包含p,但是p在集合的元素中!到底发生了什么!当然,所有的这一切都是在x域的修改后才发生的,p最终的的hashCode是在集合

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站: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号