首页 > 其他分享 >重写equals方法是否需要重写hashcode方法的总结

重写equals方法是否需要重写hashcode方法的总结

时间:2023-09-30 10:11:36浏览次数:35  
标签:map name equals hashCode hashcode 重写 public

面试时经常会被问的一个问题: 重写equals方法时是否需要重写hashCode方法,反过来又是怎样?

这篇文章将对这个问题进行了一个总结和梳理

一、考察的知识点

首先需要明确下这个问题到底在考察我们的什么知识点,涉及到equals方法和hashCode方法的问题其实都是在考察

把某个类的对象作为key存入map集合时的问题。

map集合是基于数组+链表+红黑树实现的,数组中存的是一个个Node节点,Node中有key,value,next等这些属性,

当发生hash冲突时通过next属性Node就会变成一个链表,当链表长度大于8个时就会变成红黑树但红黑树还是基于链表实现的。

使用map集合时有一个约定就是equals方法返回true的两个对象作为key时在map集合中只能存在一个

当调用put方法往map集合中添加元素时的步骤是这样的:

(1) 根据key的hashCode计算出一个数组下标, 计算时是根据hashCode值和数组容量来计算的,可以简单理解成

hash%(数组容量-1),即求余数,当然map中为了减少hash冲突(不同的hash值计算出相同的数组下标)不是这么简单算的但道理都是一样的,这里我们用取余数来简单说明:相同的hashCode算出的下标肯定一样,不同的hashcode算出的下标有可能一样也有可能不一样。

(2) 看数组下标处有没有元素,如果没有直接创建新Node节点放在此下标处

(2) 如果数组此下标处有元素,就会遍历这个下标上存的链表或者红黑树中的每个元素

(3) 调用每个元素(Node)的key的equals方法和要put的key做比较,如果equals返回true就用要put的value来替换当前这个Node上的value

(4) 直到遍历到最后一个元素也没有equals方法相等的,就新创建一个Node节点添加到原来的链表或者红黑树中,

注意这个添加在jdk7中采用的是头插法,jdk8中采用的是尾插法

二、重写equals是否需要重写hashCode方法

假设现在有一个类Person,我们重写它的equals方法让它始终返回true

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        return true;
    }

}

然后尝试创建这个类的对象作为key往map里边放,

public class Test01 {
    public static void main(String[] args) {
        HashMap<Person,Integer> map = new HashMap<>();
        Person p1 = new Person("zs");
        Person p2 = new Person("ls");
        map.put(p1,1);
        map.put(p2,2);
        //输出map中的内容
        System.out.println(map);
        //输出p1和p2equals的结果
        System.out.println(p1.equals(p2));
    }

}

控制台会输出

{com.lyy.service.Person@53d8d10a=1, com.lyy.service.Person@e9e54c2=2}
true

equals方法相等的key在map中竟然可以存在两个,这就违反了上边提到的map集合的公约,

为什么会这样呢,因为默认的hashcode方法是根据对象的地址值去计算出来的,而p1p2是两个对象地址值不一样所以计算出的hashCode不一样,根据上边put步骤中的(1)可以知道他们put时大概率会算出不同的数组下标然后放进去,走不到调用equals方法的逻辑。

所以就可以知道 当重写一个类的equals方法时就必须重写hashCode方法,保证equals返回true的两个对象它们的

hashCode值也要是相等的。

三、重写hashCode方法是否需要重写equals方法

还是上边那个Person类,这次重写hashCode方法返回一个固定值,

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return 0;
    }
}

还是用上边的test方法,当把p1和p2放入map时,因为p1和p2的hashCode是一样的,所以它俩都会放在下标0处,因为equals方法不相等所以不会相互覆盖,会组成一个链表,这种情况是没有问题的。

所以重写hashCode方法时可以不重写equals方法。

标签:map,name,equals,hashCode,hashcode,重写,public
From: https://www.cnblogs.com/chengxuxiaoyuan/p/17737643.html

相关文章

  • Java String类的 equals、==和intern()
    Java实例的生成我们都知道,java中new一个类的实例是在JVM的堆中完成的,如下图所示:在这里我们以String类为例讲解一些更为细节的东西!String生成实例的代码如下:String str=new String("hello");对于通过new产生一个字符串(假设为” hello”)时,会先去上图的常量池中查找是否已经有了......
  • 继承、方法重写
    权限修饰符 方法重写:当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)。......
  • ==与equals的区别
    Integeri= 42;Longl=42l;Doubled= 42.0;下面为true的是A(i==l)B(i==d)C(l==d)Di.equals(d)Ed.equals(l)Fi.equals(l)Gl.equals(42L)答案是G1、基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱......
  • 继承的重写
    1.继承中方法的重写重写(override)概念:在继承关系中,方法的名称一样,参数列表也一样重写(overide):方法的名称一样,参数列表【也一样】。也叫方法的覆盖,覆写。重载(overload):方法的名称一样,参数列表【不一样】方法覆盖重写的特点:创建的是子类对象,则优先用子类方法。2.方法覆盖重写的注意事......
  • C模拟CPP的方法重写(override)和多态
    1.所谓override,就是子类中重新实现了父类中的某一方法(子类和父类的同一个方法的方法体不同)2.所谓多态,最显著的一个特点就是父类指针指向不同的子类对象时,运行同一个方法会有不同的行为3.C语言模拟继承时,父类对象必须是子类对象的第一个成员4.理解了C的父类结构体指针子类结......
  • 说说hashCode() 和 equals() 之间的关系?
    每天一道面试题,陪你突击金九银十!上一篇关于介绍Object类下的几种方法时面试题时,提到equals()和hashCode()方法可能引出关于“hashCode()和equals()之间的关系?”的面试题,本篇来解析一下这道基础面试题。先祭一张图,可以思考一下为什么?介绍equals()的作用是用来判断两个对象......
  • 【C#】【Equals和ReferenceEquals】关于对象和值的问题
    在学习C#中的记录类型时,对出现的Equals和ReferenceEquals得到的不同结果表示不理解,随即进行相关资料查找。 值类型==:比较两者的“内容”是否相同,即“值”是否一样Equals:比较两者的“内容”是否相同,即“值”是否一样ReferenceEquals:返回false,因为会对值类型进行装箱再进行......
  • 10 年程序员的告诫:千万不要重写代码!!
    对重写代码说不。以下为译文:1、重写代码消耗了12个月!我们从头开始重写代码浪费的时间。你能想象在软件行业,12个月的时间没有任何新产品推出,没有任何新版本更新吗?真的,我不由自主地问自己这个问题:在这个快速发展的世界里,12月的时间能让我们做多少事情?“2015年1月20日,星......
  • vue elementplus 使用cellRenderer重写单元格,滑动滚动条渲染复选框出现错误
    使用elementplus的虚拟表格,动态加载表头的时候,第一列为复选框;但是在滚动滑动条的时候出现了一个奇怪的现象;我选择了4和5,当我滑动滚动条的时候如下: 像是复选框跟着在动; 通过跟踪代码,查出问题;在cellRenderer中打印checked的值发现问题,大滚动的时候,打印出来的都是undefined,渲......
  • 入学测试重写
    importjava.util.Scanner;publicclassWarehouseManagement{publicvoidruku(WarehouseInformation[]ware,intk){while(true){System.out.println("***********************************************************\n"+......