java hashcode重载_陷阱2:重载了equals的但没有同时重载hashCode的方法

本文探讨了在Java中,当使用自定义类如Point时,重写equals但未重写hashCode可能导致HashSet.contains()方法返回错误结果的问题。由于默认hashCode方法基于对象的内存地址,即使两个对象相等,它们的哈希码也可能不同,从而导致集合查找失败。正确的做法是同时重写equals和hashCode,确保相等的对象具有相同的哈希码,以维护集合操作的正确性。
摘要由CSDN通过智能技术生成

如果你使用上一个定义的Point类进行p1和p2的反复比较,你都会得到你预期的true的结果。但是如果你将这个类对象放入到HashSet.contains()方法中测试,你就有可能仍然得到false的结果:

Point p1 = new Point(1, 2);

Point p2 = new Point(1, 2);

HashSet coll = new HashSet();

coll.add(p1);

System.out.println(coll.contains(p2)); // 打印 false

(有可能)java学习 清软国际

软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

事实上,这个个结果不是100%的false,你也可能有返回ture的经历。如果你得到的结果是true的话,那么你试试其他的坐标值,最终你一定会得到一个在集合中不包含的结果。导致这个结果的原因是Point重载了equals却没有重载hashCode。

注意上面例子的的容器是一个HashSet,这就意味着容器中的元素根据他们的哈希码被被放入到”哈希桶 hash

buckets”中。contains方法首先根据哈希码在哈希桶中查找,然后让桶中的所有元素和所给的参数进行比较。现在,虽然最后一个Point类的版本重定义了equals方法,但是它并没有同时重定义hashCode。因此,hashCode仍然是Object类的那个版本,即:所分配对象的一个地址的变换。所以p1和p2的哈希码理所当然的不同了,甚至是即时这两个点的坐标完全相同。不同的哈希码导致他们具有极高的可能性被放入到集合中不同的哈希桶中。contains方法将会去找p2的哈希码对应哈希桶中的匹配元素。但是大多数情况下,p1一定是在另外一个桶中,因此,p2永远找不到p1进行匹配。当然p2和p2也可能偶尔会被放入到一个桶中,在这种情况下,contains的结果就为true了。java学习 清软国际

软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习

计算机软件学习

最新一个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;

}java学习 清软国际 软件工程师 如何学习java

学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

public int getX() {

return x;

}

public int getY() {

return y;

}java学习 清软国际 软件工程师 如何学习java

学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

@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());

}java学习 清软国际 软件工程师 如何学习java

学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

return result;

}

@Override public int hashCode() {

return (41 * (41 + getX()) + getY());

}

}java学习 清软国际 软件工程师 如何学习java

学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

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

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

软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

java学习 清软国际 软件工程师 如何学习java

学习java哪里好 东方清软java培训 清软国际java学习

计算机软件学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值