文档章节

hashCode() 和equals() 区别和作用

明舞
 明舞
发布于 2014/08/22 20:56
字数 1365
阅读 34
收藏 0

hashCode() 和equals() 区别和作用

HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键。 
那么Java运行时环境是如何判断HashSet中相同对象、HashMap中相同键的呢?当存储了“相同的东西”之后Java运行时环境又将如何来维护呢? 

在研究这个问题之前,首先说明一下JDK对equals(Object obj)和hashcode()这两个方法的定义和规范: 
在Java中任何一个对象都具备equals(Object obj)和hashcode()这两个方法,因为他们是在Object类中定义的。 
equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。 
hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。 
接下来有两个个关于这两个方法的重要规范(我只是抽取了最重要的两个,其实不止两个): 
规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。 
规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。 
根据这两个规范,可以得到如下推论: 
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。 
2、如果两个对象不equals,他们的hashcode有可能相等。 
3、如果两个对象hashcode相等,他们不一定equals。 
4、如果两个对象hashcode不相等,他们一定不equals。 

这样我们就可以推断Java运行时环境是怎样判断HashSet和HastMap中的两个对象相同或不同了。我的推断是:先判断hashcode是否相等,再判断是否equals。 


测试程序如下:首先我们定义一个类,重写hashCode()和equals(Object obj)方法 

Java代码    

class A {  
  
    @Override  
    public boolean equals(Object obj) {  
        System.out.println("判断equals");  
        return false;  
    }  
  
    @Override  
    public int hashCode() {  
        System.out.println("判断hashcode");  
        return 1;  
    }  
}

 

然后写一个测试类,代码如下: 

Java代码

public class Test {  
  
    public static void main(String[] args) {  
        Map<A,Object> map = new HashMap<A, Object>();  
        map.put(new A(), new Object());  
        map.put(new A(), new Object());  
          
        System.out.println(map.size());  
    }  
      
}

 

运行之后打印结果是: 

判断hashcode 
判断hashcode 
判断equals 


可以看出,Java运行时环境会调用new A()这个对象的hashcode()方法。其中: 
打印出的第一行“判断hashcode”是第一次map.put(new A(), new Object())所打印出的。 
接下来的“判断hashcode”和“判断equals”是第二次map.put(new A(), new Object())所打印出来的。 

那么为什么会是这样一个打印结果呢?我是这样分析的: 
1、当第一次map.put(new A(), new Object())的时候,Java运行时环境就会判断这个map里面有没有和现在添加的 new A()对象相同的键,判断方法:调用new A()对象的hashcode()方法,判断map中当前是不是存在和new A()对象相同的HashCode。显然,这时候没有相同的,因为这个map中都还没有东西。所以这时候hashcode不相等,则没有

必要再调用 equals(Object obj)方法了。参见推论4(如果两个对象hashcode不相等,他们 一定不equals) 
2、当第二次map.put(new A(), new Object())的时候,Java运行时环境再次判断,这时候发现了map中有两个相同的hashcode(因为我重写了A类的hashcode()方 法永远都返回1),所以有必要调用equals(Object obj)方法进行判断了。参见推论3(如果两个对象hashcode相等,他们 不一定equals),然后发现两个对象不equals(因为我重写了equals(Object obj)方法,永远都返回false)。 
3、这时候判断结束,判断结果:两次存入的对象不是相同的对象。所以最后打印map的长度的时候显示结果是:2。 



改写程序如下: 

import java.util.HashMap;  
import java.util.Map;  
  
  
class A {  
  
    @Override  
    public boolean equals(Object obj) {  
        System.out.println("判断equals");  
        return true;  
    }  
  
    @Override  
    public int hashCode() {  
        System.out.println("判断hashcode");  
        return 1;  
    }  
}  
  
  
public class Test {  
  
    public static void main(String[] args) {  
        Map<A,Object> map = new HashMap<A, Object>();  
        map.put(new A(), new Object());  
        map.put(new A(), new Object());  
          
        System.out.println(map.size());  
    }  
      
}

Java代码


运行之后打印结果是: 

判断hashcode 
判断hashcode 
判断equals 



显然这时候map的长度已经变成1了,因为Java运行时环境认为存入了两个相同的对象。原因可根据上述分析方式进行分析。 

以上分析的是HashMap,其实HashSet的底层本身就是通过HashMap来实现的,所以他的判断原理和HashMap是一样的,也是先判断hashcode再判断equals。 

所以:写程序的时候应尽可能的按规范来,不然在不知不觉中就埋下了bug!


© 著作权归作者所有

明舞
粉丝 231
博文 424
码字总数 516555
作品 0
程序员
私信 提问
Java hashCode() 和 equals()的若干问题解答

本章的内容主要解决下面几个问题: 1、 equals() 的作用是什么? 2 、equals() 与 == 的区别是什么? 3、 hashCode() 的作用是什么? 4 、hashCode() 和 equals() 之间有什么联系? 第1部分 ...

刘诗书
2017/11/27
0
0
Java之hashCode()和equals()方法

程序世界和现实世界其实是一样的,相等和相同是不同的概念,就此简要说明一下其中的含义: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么? 3 hashCode() 的作用是什么? 4 hash...

董广明
2014/04/01
594
3
hashCode() 和 equals()

第1部分 equals() 的作用 equals() 的作用是 用来判断两个对象是否相等。 equals() 定义在JDK的Object.java中。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源...

小菜鸡1
2016/08/17
39
0
hashCode和equals的区别

关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料。 有面试官会问:你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?e...

Java极客技术
08/07
0
0
== 和equals()和hashcode()区别与联系

一:==和equals()比较 值类型是存储在内存中的栈,而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中。 ==操作比较的是两个变量的值是否相等,对于引用型变量表示的...

洋哥6
2016/10/31
41
0

没有更多内容

加载失败,请刷新页面

加载更多

目标检测中 yolo 的mAP是什么含义?

mAP定义及相关概念 P => precision,即 准确率 R => recall,即 召回率 PR曲线 = >即 以 precision 和 recall 作为 纵、横轴坐标 的二维曲线。一般来说,precision 和 recall 是 鱼与熊掌 的...

小松1
3分钟前
1
0
用jdk1.8的断言来做非空判断

Assert.notNull(user, "没有获得登录用户信息"); 看源码如下: public static void notNull(Object object, String message) { if (object == null) { throw new IllegalArgum......

architect刘源源
8分钟前
2
0
免费节假日api每一时间更新 2020年 部分节假日安排

根据国务院办公厅关于2020年部分节假日安排的通知国办发明电〔2019〕16号.免费节假日api每一时间更新 2020年 部分节假日安排 http://tool.bitefu.net/jiari/ 各省、自治区、直辖市人民政府,...

xiaogg
11分钟前
3
0
2018NOIP各省一等奖分数线

提高组 普及组

SamXIAO
20分钟前
5
0
常见的PPT时间轴怎么制作,这几种方法你要知道

在PPT当中,时间轴是一个非常重要的一个版块,很多PPT会用它来表示公司的发展历程和项目进度。但是对于PPT时间轴的制作很多人做法是一条直线上添几个点,标注出事件就完成了,可是这样也太过...

TeFuiro
26分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部