热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

equals与hashCode的关系

在研究这个问题之前,首先说明一下JDK对equals(Objectobj)和hashcode()这两个方法的定义和规范:在Java中任何一个对象都具备equals(Objectobj

在研究这个问题之前,首先说明一下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)方法
1. class A {

2.
3. @Override
4. public boolean equals(Object obj) {
5. System.out.println("判断equals");
6. return false; //注意:这里:是返回了false
7. }
8. @Override
9. public int hashCode() {
10. System.out.println("判断hashcode");
11. return 1;
12. }
13.}
然后写一个测试类,代码如下:
1. public class Test {
2. public static void main(String[] args) {
3. Map map = new HashMap();
4. map.put(new A(), new Object());
5. map.put(new A(), new Object());
6.
7. System.out.println(map.size());
8. }
9. }
运行之后打印结果是:
判断hashcode
判断hashcode
判断equals
2
可以看出,Java 运行时环境会调用new A()这个对象的hashcode()方法。其中:
打印出的第一行“ 判断hashcode” 是第一次map.put(new A(), newObject())所打印出的。
接下来的“判断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(Objectobj)方法进行判断了。参见推论3(如果两个对象hashcode 相等,他们不一定equals),然后发现两个对象不equals(因为我重写了equals(Objectobj)方法,永远都返回false)。
3、这时候判断结束,判断结果:两次存入的对象不是相同的对象。所以最后打印map 的长度的时候显示结果是:2。
改写程序如下:
1. import java.util.HashMap;
2. import java.util.Map;
3. class A {
4. @Override
5. public boolean equals(Object obj) {
6. System.out.println("判断equals");
7. return true; //注意:这里:是返回了true,跟上面的不同
8. }
9. @Override
10. public int hashCode() {
11. System.out.println("判断hashcode");
12. return 1;
13. }
14.}
15.public class Test {
16. public static void main(String[] args) {
17. Map map = new HashMap();
18. map.put(new A(), new Object());
19. map.put(new A(), new Object());
20. System.out.println(map.size());
21. }
22.}
运行之后打印结果是:
判断hashcode
判断hashcode
判断equals
1
显然这时候map 的长度已经变成1 了,因为Java 运行时环境认为存入了两个相同的对象。原因可根据上述分析方式进行分析。
以上分析的是HashMap,其实HashSet 的底层本身就是通过HashMap 来实现的,所以他的判断原理和HashMap 是一样的,也是先判断hashcode 再判断equals。


推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
信妹氵V
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有