【转】 如何重写hashCode()和equals()方法
转自:http://blog.csdn.net/neosmith/article/details/17068365
hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们就讨论一下如何正解理解和使用这2个方法.
如何重写equals()方法
- It is reflexive: for any non-null reference value
x,x.equals(x)should returntrue. - It is symmetric: for any non-null reference values
xandy,x.equals(y)should returntrueif and
only ify.equals(x)returnstrue. - It is transitive: for any non-null reference values
x,y, andz, ifx.equals(y)returnstrueandy.equals(z)returnstrue,
thenx.equals(z)should returntrue. - It is consistent: for any non-null reference values
xandy, multiple invocations ofx.equals(y)consistently returntrueor
consistently returnfalse, provided no information used inequalscomparisons on the objects is modified. - For any non-null reference value
x,x.equals(null)should returnfalse.
这段话用了很多离散数学中的术数.简单说明一下:
- class Coder {
- private String name;
- private int age;
- // getters and setters
- }
我们想要的是,如果2个程序员对象的name和age都是相同的,那么我们就认为这两个程序员是一个人.这时候我们就要重写其equals()方法.因为默认的equals()实际是判断两个引用是否指向内在中的同一个对象,相当于 == . 重写时要遵循以下三步:
- if(other == this)
- return true;
2. 使用instanceof运算符判断 other 是否为Coder类型的对象.
- if(!(other instanceof Coder))
- return false;
3. 比较Coder类中你自定义的数据域,name和age,一个都不能少.
- Coder o = (Coder)other;
- return o.name.equals(name) && o.age == age;
看到这有人可能会问,第3步中有一个强制转换,如果有人将一个Integer类的对象传到了这个equals中,那么会不会扔ClassCastException呢?这个担心其实是多余的.因为我们在第二步中已经进行了instanceof
的判断,如果other是非Coder对象,甚至other是个null, 那么在这一步中都会直接返回false,
从而后面的代码得不到执行的机会.
如何重写hashCode()方法
hashCode method whenever this method(equals) is overridden, so as to maintain the generalcontract for the
hashCode method, which states that equal objects must have equal hash codes."Java>中给出了一个能最大程度上避免哈希冲突的写法,但我个人认为对于一般的应用来说没有必要搞的这么麻烦.如果你的应用中HashSet中需要存放上万上百万个对象时,那你应该严格遵循书中给定的方法.如果是写一个中小型的应用,那么下面的原则就已经足够使用了:
- @Override
- public int hashCode() {
- int result = 17;
- result = result * 31 + name.hashCode();
- result = result * 31 + age;
- return result;
- }
其中int result = 17你也可以改成20, 50等等都可以.看到这里我突然有些好奇,想看一下String类中的hashCode()方法是如何实现的.查文档知:
String object is computed as
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.)"
重写equals()而不重写hashCode()的风险
table大致相当于哈希表与链表的结合体.即在每个bucket上会挂一个链表,链表的每个结点都用来存放对象.Java通过hashCode()方法来确定某个对象应该位于哪个bucket中,然后在相应的链表中进行查找.在理想情况下,如果你的hashCode()方法写的足够健壮,那么每个bucket将会只有一个结点,这样就实现了查找操作的常量级的时间复杂度.即无论你的对象放在哪片内存中,我都可以通过hashCode()立刻定位到该区域,而不需要从头到尾进行遍历查找.这也是哈希表的最主要的应用.
o)方法时,首先会根据o.hashCode()的返回值定位到相应的bucket中,如果该bucket中没有结点,则将 o
放到这里,如果已经有结点了, 则把 o 挂到链表末端.同理,当调用contains(Object
o)时,Java会通过hashCode()的返回值定位到相应的bucket中,然后再在对应的链表中的结点依次调用equals()方法来判断结点中的对象是否是你想要的对象.
- Coder c1 = new Coder("bruce", 10);
- Coder c2 = new Coder("bruce", 10);
假定我们已经重写了Coder的equals()方法而没有重写hashCode()方法:
- @Override
- public boolean equals(Object other) {
- System.out.println("equals method invoked!");
- if(other == this)
- return true;
- if(!(other instanceof Coder))
- return false;
- Coder o = (Coder)other;
- return o.name.equals(name) && o.age == age;
- }
然后我们构造一个HashSet,将c1对象放入到set中:
- Set<Coder> set = new HashSet<Coder>();
- set.add(c1);
再执行:
- System.out.println(set.contains(c2));
B 的hashCode()要返回相同的值.
我让hashCode()每次都返回一个固定的数行吗
- @Override
- public int hashCode() {
- return 10;
- }
如果这样的话,HashMap, HashSet等集合类就失去了其 "哈希的意义".用<Effective
Java>中的话来说就是,哈希表退化成了链表.如果hashCode()每次都返回相同的数,那么所有的对象都会被放到同一个bucket中,每次执行查找操作都会遍历链表,这样就完全失去了哈希的作用.所以我们最好还是提供一个健壮的hashCode()为妙.
【转】 如何重写hashCode()和equals()方法的更多相关文章
- 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。
我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...
- (转)为什么要重写 hashcode 和 equals 方法?
作者丨hsm_computer cnblogs.com/JavaArchitect/p/10474448.html 我在面试Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候 ...
- HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法
之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...
- 为什么要重写hashcode和equals方法
我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...
- 重写hashcode和equals方法
重写hashcode和equals方法 简乐君 2019-05-07 21:55:43 35481 收藏 191分类专栏: Java 文章标签: equals() hashcode()版权 一.前言我 ...
- 如何重写hashCode()和equals()方法
hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们就讨论一下如何正解理解和使用这2个方法. 如何重写equal ...
- Java 重写 hashCode() 和 equals() 方法
1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...
- 【java编程】重写HashCode和equals方法
[一]重写equals方案的规则 equals方法本来的原则 1.类的每个实例本质上都是唯一的. 2.不关心类是否提供了“逻辑相等”的测试功能 3.超类已经覆盖了equals,从超类继承过来的行为对于 ...
- Hibernate中用到联合主键的使用方法,为何要序列化,为何要重写hashcode 和 equals 方法
联合主键用Hibernate注解映射方式主要有三种: 第一.将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,再将该类注解为 ...
随机推荐
- 新版的nuget包 PackageLicense 这样写
Intro 最近编译类库项目的时候发现总是有个 licenseUrl 的警告,警告信息如下: warning NU5125: The 'licenseUrl' element will be depr ...
- SQL Server查看视图定义总结
在SQL Server中如何查看数据库视图的定义呢? 其实官方文档已经有一个较详细的总结了,这里在官方文档的基础上,我们再深入展开分析一下,例如如何获取系统视图的定义.知其然知其所以然吗. 1:使 ...
- MyBatis批量修改操作
1.需求 后台管理页面,查询频道列表,需要批量修改频道的状态,批量上线和下线 2.MyBatis配置 这是mysql的配置,注意需要加上&allowMultiQueries=true配置 jd ...
- UPUPW配置
UPUPW下载地址 https://sourceforge.net/projects/upupw/files/ANK/?tdsourcetag=s_pctim_aiomsg 配置 在这里插入图片描述
- Python生成器、推导式之前襟后裾
生成器 函数体内有yield选项的就是生成器,生成器的本质是迭代器,由于函数结构和生成器结构类似,可以通过调用来判断是函数还是生成器,如下: def fun(): yield "我是生成器& ...
- 【原】Java学习笔记001 - JAVA开发环境搭建
1.JDK下载并安装,以jdk-7u45-windows-i586.exe为例(注意JDK的安装和JRE的安装是分开的) 2.“我的电脑”右键属性,找到“高级系统设置”,找到“高级”tab下的“环境变 ...
- c/c++ 多线程 层级锁
多线程 层级锁 当要同时操作2个对象时,就需要同时锁定这2个对象,而不是先锁定一个,然后再锁定另一个.同时锁定多个对象的方法:std::lock(对象1.锁,对象2.锁...) 但是,有的时候,并不能 ...
- [RHEL 6]GPT分区--parted
对于2T以上的硬盘,划分分区表需要GPT分区,RHEL 6中使用parted进行分区 用法:parted [选项]... [设备 [命令 [参数]...]...] 将带有“参数”的命令应用于“设备”. ...
- Django REST framework基础:解析器和渲染器
解析器 解析器的作用 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己可以处理的数据.本质就是对请求体中的数据进行解析. 在了解解析器之前,我们要先知道Accept以及ContentTy ...
- tcping ,一个好用的TCP端口检测工具
1.常用的用法(windows) tcp -w 10 -t -d -i 5 -j --color 81.156.165.66 443 2. http模式 -u,与-h命令连用,每一行输出目标的url ...