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 ...
随机推荐
- lenet-5
https://blog.csdn.net/happyorg/article/details/78274066 深度学习 CNN卷积神经网络 LeNet-5详解 2017年10月18日 16:04:3 ...
- 688. Knight Probability in Chessboard棋子留在棋盘上的概率
[抄题]: On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to make exa ...
- linux之重定向命令
1.shell重定向概念:shell重定向包含输出重定向和输入重定向 何为输入输出方向?何为标准输入输出方向? 标准输入方向:从键盘读取用户输入的数据,然后再把数据拿到程序(C语言程序.Shell 脚 ...
- Add-Migration : 无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
解决办法: PM>Import-Module C:\Users\Administrator.MACKJON\.nuget\packages\entityframework\6.2.0\tools ...
- android端如何实现设置颜色透明度?
今 天测试反馈设置的色值跟设计图不一致,其实是一个很简单的设置,黑色,70%透明. 而我是这么设置的:<solid android:color="#30000000"/> ...
- android app主程序启动前加载图片
android app加载启动图片需要新创建一个activity,在主activity先加载图片activity,展示过程结束后,显示主activity.具体流程如下: 一.创建图片activity的 ...
- Pandas 合并 concat
pandas处理多组数据的时候往往会要用到数据的合并处理,使用 concat是一种基本的合并方式.而且concat中有很多参数可以调整,合并成你想要的数据形式. 1.axis(合并方向):axis=0 ...
- 20172325 2018-2019-2 《Java程序设计》第六周学习总结
20172325 2018-2019-2 <Java程序设计>第六周学习总结 教材学习内容总结 本周学习第十章--树 1.什么是树 (1)树是一种数据结构,与之前学过的栈.队列和列表这些线 ...
- 别人的Linux私房菜(12)正则表达式与文件格式化处理
vi gerp awk sed支持正则表达式 cp ls不支持,只能使用bash本身的通配符 正则表达式分为基础正则表达式和拓展正则表达式 使用正则表达式注意语系的影响 http://cn.lin ...
- spass按位置编码,进行排序题处理与分析
本范例即需建立Q4_1至Q4_4 等四个变项, 各变量的数值则是排序的内容,共有0.1.2.3.4 等五种可能,0代表该选项没有被受测者选取,1.2.3.4分别代表被受测者指为第一至第四顺位. htt ...