hashcode和equals方法的区别和联系
说到 hashcode就要和Java中的集合,HashSet,HashMap 关系最为密切。
首先附录两张Java的集合结构图:

图二:(上图的简化版)

从Set集合的特点说起 & Set是如何去除重复元素的:
Set:元素不可以重复,是无序的。 Set接口中的方法和Collection一致(看上面的集合框架图)。
|--HashSet: 内部数据结构是哈希表 ,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。
hashCode值和对象的内容是存储在hash表中的。
如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
如果为true,视为相同元素,不存储。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。一般情况下,如果定义的类会产生很多对象,比如人(Person类),学生(Student类),书(Book类),通常都需要覆盖equals,hashCode方法。
建立对象判断是否相同的依据。

哈希算法是底层windows做的,而且针对不同的对象有不同的哈希算法运算。
java类中有的哈希算法是native用的windows底层 的,有的根据对象的不同进行了重写。
哈希表:哈希这种算法会算出很多的值,把这些值存储起来形成一个表。表中有对应关系。
哈希表的结构还是数组。只是哈希这种算法对数组进行了优化。
哈希算法有一种最常见的算法就是取余。
哈希表中不能有重复的元素。
哈希表是如何判断元素是否是重复的? 举例一种取余的HashCode算法原理:

“ab”和”ba”产生的哈希值是一样的,取余之后都是5,但是内容不一样,哈希值对这样的情况也有对应的方法,在5角标出“挂”一个”ba”。
在list集合remove和contains都要判断相不相同,都是用的equals,不用hashcode
如果到了Set集合,要删除一个元素,要依据该元素是否和该容器中的元素是否相同。HashSet依据对象的hashcode和equals。
代码举例,Set中存储自定义的类对象:
①原始的方式,不重写equals也不重写hashcode。
Person.java
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
CollectionTest.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class CollectionTest {
public static void main(String[] args) {
//单个对象
Person p1 = new Person("kxh",22);
Person p2 = new Person("kxh",22);
System.out.println("p1 == p2:" + (p1 == p2));
System.out.println("p1.equals(p2):" + p1.equals(p2));
//List集合
ArrayList<Person> arrayList = new ArrayList<Person>();
arrayList.add(new Person("lisi1",11));
arrayList.add(new Person("lisi2",12));
arrayList.add(new Person("lisi3",13));
arrayList.add(new Person("lisi4",14));
arrayList.add(new Person("lisi4",14));
//HashMap集合
HashMap<Person,Object> hashMap = new HashMap<Person,Object>();
hashMap.put(new Person("lisi1",11),new Object());
hashMap.put(new Person("lisi2",12),new Object());
hashMap.put(new Person("lisi3",13),new Object());
hashMap.put(new Person("lisi4",14),new Object());
hashMap.put(new Person("lisi4",14),new Object());
//HashSet集合
HashSet<Person> hashSet = new HashSet<Person> ();
hashSet.add(new Person("lisi1",11));
hashSet.add(new Person("lisi2",12));
hashSet.add(new Person("lisi3",13));
hashSet.add(new Person("lisi4",14));
hashSet.add(new Person("lisi4",14)); //遍历ArrayList集合
System.out.println("遍历ArrayList集合------");
Iterator arrayListIterator = arrayList.iterator();
while(arrayListIterator.hasNext()){
Person p = (Person) arrayListIterator.next();
System.out.println(p.getName()+"---"+p.getAge());
} //遍历HashMap集合
System.out.println("遍历HashMap集合------");
Set<Entry<Person, Object>> entrySet = hashMap.entrySet();
Iterator entrySetIterator = entrySet.iterator();
while(entrySetIterator.hasNext()){
Map.Entry entry = (Map.Entry)entrySetIterator.next();
System.out.println(entry.getKey()+"---"+entry.getValue());
} //遍历HashSet集合
System.out.println("遍历HashSet集合------");
Iterator hashSetIterator = hashSet.iterator();
while(hashSetIterator.hasNext()){
Person p = (Person) hashSetIterator.next();
System.out.println(p.getName()+"---"+p.getAge());
}
}
}
程序输出:
p1 == p2:false
p1.equals(p2):false
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
cn.cdv.collection.Person@52e922---java.lang.Object@1b84c92
cn.cdv.collection.Person@10dea4e---java.lang.Object@1c7c054
cn.cdv.collection.Person@1db9742---java.lang.Object@12204a1
cn.cdv.collection.Person@106d69c---java.lang.Object@a298b7
cn.cdv.collection.Person@25154f---java.lang.Object@14991ad
遍历HashSet集合------
lisi1---11
lisi2---12
lisi4---14
lisi4---14
lisi3---13
ArrayList中可以存储重复元素,HashMap中使用了两个“一样的”new Person("lisi4",14)作为key,同一个key在HashMap中只能有一个,HashSet中存储进去了两个“lisi4 14”又是集合Set ,Set集合中不会再存储相同的元素。为什么出现这种情况。
①这是Map和Set存储用户自定义对象。
②Person类继承的是Object,每new一个Person都有不同的地址值,hashcode不同,对于Set集合来说是不同的元素,对Map来说是不同的Key。
③你自己定义的只要名字和年龄一样就是不同的对象这个规则程序现在是不知道的。需要你自己去定义,完善。
②只重写equals方法,在equals方法中判断Person对象的name和age属性值是否相等来判断对象是否相同。
public class Person extends Object {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if(this == obj){//当判断完hashCode()方法之后hah值相同,如果内容也相同,使用==这样结束equals语句中的判断。
return true;
}
if(!(obj instanceof Person)){
throw new ClassCastException("类型错误");
}
//运行到这里说明两者 相等,打印输出。。。
System.out.println(this+"....重写equals判断相同....."+obj);
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String toString(){
return name +":"+ age;
}
}
程序输出:
p1 == p2:false
kxh:22....重写equals判断相同.....kxh:22
p1.equals(p2):true
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi3:13---java.lang.Object@1b84c92
lisi4:14---java.lang.Object@1c7c054
lisi1:11---java.lang.Object@12204a1
lisi2:12---java.lang.Object@a298b7
lisi4:14---java.lang.Object@14991ad
遍历HashSet集合------
lisi1---11
lisi2---12
lisi4---14
lisi4---14
lisi3---13
结果分析:因为Person两个对象的age和name属性相等,而且又是通过覆盖equals方法来判断的,所示p1.equals(p2) 为true。
只重写equals方法,加入ArrayList,HashMap和HashSet的元素都全部打印出来。
③通过以上代码我们知道equals方法已经生效。接下来我们在覆盖一下hashCode方法(通过age和name属性来生成hashcode)并不覆盖equals方法,其中Hash码是通过age和name生成的。
public class Person extends Object {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
/*
* hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,
* 返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
*/
@Override
public int hashCode() {
System.out.println(this+".......hashCode的值:" + name.hashCode()+age*27);
return name.hashCode()+age*27;
}
public String toString(){
return name +":"+ age;
}
}
测试类不变,运行测试类,程序输出:
p1 == p2:false
p1.equals(p2):false
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi2:12---java.lang.Object@1db9742
lisi1:11---java.lang.Object@106d69c
lisi4:14---java.lang.Object@52e922
lisi4:14---java.lang.Object@25154f
lisi3:13---java.lang.Object@10dea4e
遍历HashSet集合------
lisi2---12
lisi1---11
lisi4---14
lisi4---14
lisi3---13
上面ArrayList,HashMap,HashSet总共三组,但是只打印了两组数据的hashcode。由集合的特性可知,这两组是HashMap和HashSet添加数据时打印的,ArrayList中添加数据是不会判断hashcode值的。
我们并没有覆盖equals方法只覆盖了hashCode方法,对于HashMap两个对象中有两个new Person("lisi4",14)作为key,对于HashSet中放入有两个new Person("lisi4",14),
虽然两个对象new Person("lisi4",14)的hashCode一样,但是根据比较原则,先比较hashcode,如果hashcode相同再比较equals,很明显两个new Person("lisi4",14) 对应的值为false,所以加入到HashMap和HashSet的值全部打印出来。
④既覆盖hashCode() 又重写equals()方法
public class Person extends Object {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
/*
* hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,
* 返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
*/
@Override
public int hashCode() {
System.out.println(this+".......hashCode的值:" + name.hashCode()+age*27);
return name.hashCode()+age*27;
}
@Override
public boolean equals(Object obj) {
if(this == obj){//当判断完hashCode()方法之后hah值相同,如果内容也相同,使用==这样结束equals语句中的判断。
return true;
}
if(!(obj instanceof Person)){
throw new ClassCastException("类型错误");
}
//运行到这里说明两者 相等,打印输出。。。
System.out.println(this+"....重写equals判断相同....."+obj);
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String toString(){
return name +":"+ age;
}
}
测试类不变,运行输出:
p1 == p2:false
kxh:22....重写equals判断相同.....kxh:22
p1.equals(p2):true
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi4:14....重写equals判断相同.....lisi4:14
lisi1:11.......hashCode的值:102982142297
lisi2:12.......hashCode的值:102982143324
lisi3:13.......hashCode的值:102982144351
lisi4:14.......hashCode的值:102982145378
lisi4:14.......hashCode的值:102982145378
lisi4:14....重写equals判断相同.....lisi4:14
遍历ArrayList集合------
lisi1---11
lisi2---12
lisi3---13
lisi4---14
lisi4---14
遍历HashMap集合------
lisi2:12---java.lang.Object@1db9742
lisi1:11---java.lang.Object@106d69c
lisi4:14---java.lang.Object@52e922
lisi3:13---java.lang.Object@25154f
遍历HashSet集合------
lisi2---12
lisi1---11
lisi4---14
lisi3---13
通过结果可以看出,hashcode和equals都复写之后才真正保证了唯一性,复写equals方法必须复写hashcode方法。

附录另外有价值的博客:
http://blog.csdn.net/michaellufhl/article/details/5833188
http://blog.csdn.net/jiangwei0910410003/article/details/22739953
http://www.cnblogs.com/DreamDrive/p/5431725.html
http://www.cnblogs.com/lulipro/p/5628750.html
hashcode和equals方法的区别和联系的更多相关文章
- 一、基础篇--1.1Java基础-hashCode和equals方法的区别和联系
hashCode和equals方法的区别和联系 两个方法的定义 equals(Object obj)方法用来判断两个对象是否"相同",如果"相同"则返回tr ...
- hashCode和equals方法的区别与联系
hashCode()方法和equal()方法的作用其实一样,在Java里都是用来对比两个对象是否相等: (1)equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比 ...
- 关于hashcode和equals方法说明
一.前言 我们都知道,要比较两个对象是否相等时需要调用对象的equals()方法,即判断对象引用所指向的对象地址是否相等,对象地址相等时,那么与对象相关的对象句柄.对象头.对象实例数据.对象类型数据等 ...
- 重写hashcode和equals方法
重写hashcode和equals方法 简乐君 2019-05-07 21:55:43 35481 收藏 191分类专栏: Java 文章标签: equals() hashcode()版权 一.前言我 ...
- 用HashSet的add方法谈hashcode和equals方法重写
本文主要通过用HashSet的add方法讲一下hashCode和equals方法重写.错误的地方望指正. 1.了解HashSet的add方法 了解一个方法的好办法是看源码,所以先看源码 private ...
- Java 中正确使用 hashCode 和 equals 方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- 使用hashCode()和equals()方法 - Java
在这篇文章中,我将指出我对hashCode()和equals()方法的理解.我将讨论它们的默认实现以及如何正确地覆盖它们.我还将使用Apache Commons包中的实用工具类来实现这些方法. has ...
- K:java中的hashCode和equals方法
hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...
- Java学习从菜鸟变大鸟之一 hashCode()和equals()的本质区别和联系
在学习java,根据视频做实例的过程中,对equals和hashcode两个方法理解稍微深刻一点,主要是它们两个很容易混淆,容易出错,自己又通过网上的资料学习,和大家分享 equals()方法 equ ...
随机推荐
- UVA10600 次小生成树
题目链接:https://vjudge.net/problem/UVA-10600 题意:叫我们求出最小生成树的边权之和 和次小生成树的边权之和. 思路:我们可以先求出最小生成树,这个不难,如果要求次 ...
- 图片转base64上传,视频同理。
body: <input type="file" id="img" type="file" onchange="up()&q ...
- 259. 3Sum Smaller小于版3sum
[抄题]: Given an array of n integers nums and a target, find the number of index triplets i, j, k with ...
- 186. Reverse Words in a String II 翻转有空格的单词串 里面不变
[抄题]: Given an input string , reverse the string word by word. Example: Input: ["t"," ...
- 真·浅谈treap树
treap树是一种平衡树,它有平衡树的性质,满足堆的性质,是二叉搜索树,但是我们需要维护他 为什么满足堆的性质?因为每个节点还有一个随机权值,按照随机权值维持这个堆(树),可以用O(logn)的复杂度 ...
- bittorrent 学习(一) 种子文件分析与bitmap位图
终于抽出时间来进行 BITTORRENT的学习了 BT想必大家都很熟悉了,是一种文件分发协议.每个下载者在下载的同时也在向其他下载者分享文件. 相对于FTP HTTP协议,BT并不是从某一个或者几个指 ...
- python2.x 到 python3.x 中“url”部分变化
这部分是笔者在亲身项目中遇到的一些变化,并不全,后面将会更新. (1) urllib.urlopen 改为: urllib.request.urlopen (2) urllib2 删除 ...
- 主引导扇区MBR的解析
http://blog.chinaunix.net/uid-24774106-id-3340397.html 最近排查一个USB相关的故障,由于信息安全就不多说工作上的事情了,顺路学习了MBR的相关知 ...
- ABP框架系列之五十四:(XSRF-CSRF-Protection-跨站请求伪造保护)
Introduction "Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a maliciou ...
- Oracle实现like多个值的查询
问题背景描述: 某天客户有一个需求,给定一批的手机号码或者电话号码,查询出相关的通话记录,以及相关的一些信息. 客户给定的被叫号码如图所示: 查询出来的结果如下图所示(本批次的结果不是上图导入的结 ...