[改善Java代码]覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先来看如下代码:
public static void main(String[] args) {
// Person类的实例作为Map的key
Map<Person, Object> map = new HashMap<Person, Object>() {
{
put(new Person("张三"), new Object());
}
};
// Person类的实例作为List的元素
List<Person> list = new ArrayList<Person>() {
{
add(new Person("张三"));
}
};
// 列表中是否包含
boolean b1 = list.contains(new Person("张三"));
// Map中是否包含
boolean b2 = map.containsKey(new Person("张三"));
}
代码中的Person类与上一建议相同(http://www.cnblogs.com/DreamDrive/p/5431603.html),euqals方法完美无缺。在这段代码中,我们在声明时直接调用方法赋值,这其实也是一个内部匿名类的操作(下一个建议会详细说明)。现在的问题是b1和b2这两个boolean值是否都为true?
我们先来看b1,Person类的equals覆写了,不再判断两个地址是否相等,而是根据人员的姓名来判断两个对象是否相等,所以不管我们的new Person(“张三”)产生了多少个对象,它们都是相等的。把“张三”对象放入List中,再检查List中是否包含,那结果肯定是true了。
接着来看b2,我们把张三这个对象作为了Map的键(Key),放进去的对象是张三,检查的对象还是张三,那应该和List的结果相同了,但是很遗憾,结果是false。原因何在呢?
原因就是HashMap的底层处理机制是以数组的方式保存Map条目(Map Entry)的,这其中的关键是这个数组下标的处理机制:依据传入元素hashCode方法的返回值决定其数组的下标,如果该数组位置上已经有了Map条目,且与传入的键值相等则不处理,若不相等则覆盖;如果数组位置没有条目,则插入,并加入到Map条目的链表中。同理,检查键是否存在也是根据哈希码确定位置,然后遍历查找键值的。
接着深入探讨,那对象元素的hashCode方法返回的是什么值呢?它是一个对象的哈希码,是由Object类的本地方法生成的,确保每个对象有一个哈希码(这也是哈希算法的基本要求:任意输入k,通过一定算法f(k),将其转换为非可逆的输出,对于两个输入k1和k2,要求若k1=k2,则必须f(k1)=f(k2),但也允许k1≠k2,f(k1)=f(k2)的情况存在)。
那回到我们的例子上,由于我们没有重写hashCode方法,两个张三对象的hashCode方法返回值(也就是哈希码)肯定是不相同的了,在HashMap的数组中也就找不到对应的Map条目了,于是就返回了false。
问题清楚了,修改也非常简单,重写一下hashCode方法即可,代码如下:
class Person {
/*其他代码相同,不再赘述*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(name).toHashCode();
}
}
其中HashCodeBuilder是org.apache.commons.lang.builder包下的一个哈希码生成工具,使用起来非常方便,诸位可以直接在项目中集成。(为什么不直接写hashCode方法?因为哈希码的生成有很多种算法,自己写麻烦,事儿又多,所以采用拿来主义是最好的方法。)
[改善Java代码]覆写equals方法必须覆写hashCode方法的更多相关文章
- 为什么覆写equals必须要覆写hashCode?
============================================= 原文链接: 为什么覆写equals必须要覆写hashCode? 转载请注明出处! ============= ...
- JAVA中重写equals()方法为什么要重写hashcode()方法?
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...
- 一文搞懂--Java中重写equals方法为什么要重写hashcode方法?
Java中重写equals方法为什么要重写hashcode方法? 直接看下面的例子: 首先我们只重写equals()方法 public class Test { public static void ...
- 为什么重写equals()方法就必须重写hashCode()方法
hashCode()和equals()保持一致,如果equals方法返回true,那么两个对象的hasCode()返回值必须一样.如果equals方法返回false,hashcode可以不一样,但是这 ...
- [改善Java代码]覆写equals方法时不要识别不出自己
建议45: 覆写equals方法时不要识别不出自己 我们在写一个JavaBean时,经常会覆写equals方法,其目的是根据业务规则判断两个对象是否相等,比如我们写一个Person类,然后根据姓名判断 ...
- [改善Java代码]equals应该考虑null值的情景
建议46: equals应该考虑null值情景 继续上一建议的问题,我们解决了覆写equals的自反性问题,是不是就很完美了呢?再把main方法重构一下: public class Client { ...
- [改善Java代码]在equals中使用getClass进行类型判断
建议47: 在equals中使用getClass进行类型判断 本节我们继续讨论覆写equals的问题.这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JEE中J ...
- [改善Java代码]用枚举实现工厂方法模式更简洁
工厂方法模式(Factory Method Patter)是"创建对象的接口",让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类.工厂方法模式在我们的开发工作中,经常会用到 ...
- 改善JAVA代码01:考虑静态工厂方法代替构造器
前言 系列文章:[传送门] 每次开始新的一本书,我都会很开心.新书新心情. 正文 静态工厂方法代替构造器 说起这个,好多可以念叨的.做了一年多的项目,慢慢也有感触. 说起构造器 大家很明白,构造器 ...
随机推荐
- 48种CIFilter
48种CIFilter CIAdditionCompositing //影像合成 CIAffineTransform //仿射变换 CICheckerboardGe ...
- FOR XML PATH的用法
USE [ChangHongWMS612]GO/****** Object: StoredProcedure [dbo].[st_WMS_SelStockInBillList] Script Date ...
- iOS开发-block使用与多线程
Block Block封装了一段代码,可以在任何时候执行 Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值. 苹果官方建议尽量多用block.在多线程.异步任务.集合遍历. ...
- Line去年营收超5亿美元 远超竞争对手WhatsApp
原文地址: http://news.cnblogs.com/n/206072/ 凭借着修改表情取悦国际用户的做法,日本移动消息应用 Line 在全球的用户总数已经超过 4 亿.Line.微信.What ...
- 当LinkButton无效时,光标不显示为手型
在Flex组件LinkButton里,我们可以用useHandCursor属性来控制是否使用手型光标.现在我们要实现在LinkButton的enable=false时,useHandCursor=fa ...
- Posting data to a HttpHandler greater then ~29MB gives a 404 error
1down votefavorite 1 I am testing a HttpHandler that accepts XML. It works fine when a small amount ...
- QM课程02-外部功能
质量计划 · 对质量计划和检验计划进行基本数据的管理 · 物料说明 · 检验计划 质量检验 · 触发检验 · 具有检验计划选择和样本计算的检验处理 · 打印采样和检验的车间文档 · 记录结果和缺陷 · ...
- UVALive 7070 The E-pang Palace 暴力
The E-pang Palace Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/problem ...
- delphi ExecWB
TWebBrowser.ExecWB 关键点 procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT); overload; 实现过程 ...
- SOA面向服务化编程架构(dubbo)
dubbo 是阿里系的技术.并非淘宝系的技术啦,淘宝系的分布式服务治理框架式HSF啦 ,只闻其声,不能见其物.而dubbo是阿里开源的一个SOA服务治理解决方案,dubbo本身 集成了监控中心,注 ...