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
2

可以看出,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。

改写程序如下:

Java代码

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());    }    }    

运行之后打印结果是:

判断hashcode
判断hashcode
判断equals
1

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

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

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

hashCode() 和equals() 区别和作用相关推荐

  1. hashcode的作用_看似简单的hashCode和equals面试题,竟然有这么多坑!

    hashCode()方法和equals()区别与联系这到面试题,看似简单,根据以往面试星友的情况来说,绝大部分人都不能很好的回答出来,要么没有逻辑,想到一句就说一句,要么抓不住重点,答非所问.从这个很 ...

  2. 看似简单的hashCode和equals面试题,竟然有这么多坑!

    作者:徐刘根,大家都喊我根哥! hashCode()方法和equals()区别与联系这到面试题,看似简单,根据以往面试星友的情况来说,绝大部分人都不能很好的回答出来,要么没有逻辑,想到一句就说一句,要 ...

  3. equals的效率_看似简单的hashCode和equals面试题,竟然有这么多坑!

    点击上方"Java后端技术",选择"置顶或者星标" 你关注的就是我关心的! hashCode()方法和equals()区别与联系这到面试题,看似简单,根据以往面 ...

  4. (转)从一道面试题彻底搞懂hashCode与equals的作用与区别及应当注意的细节

    背景:学习java的基础知识,每次回顾,总会有不同的认识.该文系转载 最近去面试了几家公司,被问到hashCode的作用,虽然回答出来了,但是自己还是对hashCode和equals的作用一知半解的, ...

  5. 二十六、深入HashCode与equals的区别(上篇)

    @Author:Runsen @Date:2020/6/2 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...

  6. 深入理解equals和hashCode关系和区别

    深入理解equals和hashCode关系和区别 直入主题: 区别: 1.他们判断对象相同的方式不一样: 2.他们判断对象是否相等的准确率不一样: 改写equals时总是要改写hashcode 分享一 ...

  7. java中equals,hashcode和==的区别

    原文地址http://blog.csdn.net/hla199106/article/details/46907725 1.== java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型 ...

  8. hashCode与equals的区别与联系

    一.equals方法的作用 1.默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一 ...

  9. hashcode的作用_【09期】说说hashCode() 和 equals() 之间的关系?

    上一篇关于介绍Object类下的几种方法时面试题时,提到equals()和hashCode()方法可能引出关于"hashCode() 和 equals() 之间的关系?"的面试题, ...

最新文章

  1. Kali渗透测试——快速查找Metasploit的模块
  2. [BZOJ4399]魔法少女LJJ
  3. ##API(七)————日期操作类(二)
  4. 【GISER Painter】矢量切片(Vector tile)
  5. 回味颜宁演讲:“勇敢做独一无二的你”
  6. tf 矩阵行和列交换_tf.transpose函数的用法讲解
  7. 从头认识Spring-1.14 SpEl表达式(1)-简单介绍与嵌入值
  8. 算法面试题_求给定字符串的排列、组合、八皇后问题
  9. Activiti Cloud 开始
  10. 整理Oracle日期时间函数
  11. debug HTTP的一个GUI工具NetTool
  12. 苹果开发者三类账号说明
  13. 职中c语言课程,C语言课件下载【深圳职业技术学院】
  14. MSMS探针卡市场现状及未来发展趋势
  15. 如何写一份优秀的投资计划书
  16. meta标签下http-equiv 属性详解
  17. Word 在试图打开文件时遇到错误 解决办法
  18. 技术探秘:华为云瑶光何以定方向
  19. ingest-attachment理解误区
  20. 计算机电路计数器pl什么意思,计数器的原理为什么1下来是2.而且频率是一样的.它是怎么进位的.它的电路原理是什么...

热门文章

  1. 寄存器、cache、内存、硬盘之间的千丝万缕
  2. pymysql语法_如何使用PyMySQL模块进行增删改查?
  3. python编程单词排序_Python读取英文文件并记录每个单词出现次数后降序输出示例...
  4. TVS二极管,双向封装,如何选型?
  5. 云计算机房所用服务器,什么是云机房、云服务器、云主机?这三者有什么区别?...
  6. Java平滑处理什么意思_为何要进行数据平滑处理?
  7. linux 端口 837,《Linux菜鸟入门》系统日志
  8. android kernel控制台初始化过程
  9. oracle查询重复数据出现次数
  10. TCP/IP详解学习笔记(8)-DNS域名系统