首页 > 其他 > 详细

为什么重写equals方法,还必须要重写hashcode方法

时间:2019-10-27 19:23:40      阅读:123      评论:0      收藏:0      [点我收藏+]

一、equals方法和hashcode的关系

根据Object.hashCode的通用约定

  1. 如果两个对象相同(equals方法返回true),那么hashcode也相等。(图1
  2. 如果两个对象的hashcode相等,这两个对象不一定相同,因为可能发生了hash冲突。(图2

 

 

举个例子:下图的hash算法为   hashcode = num % 4

 技术分享图片

 

                                                        图1

 

上图的两个对象相同(意思就是同一个对象),hashcode的值都是1.

 技术分享图片

 

                                                              2

 

上图的两个对象的hashcode的值都是1,但是一个对象是13,一个对象是17,它们发生了hash冲突。

二、什么情况下,需要重写equals方法和hashcode方法?

比如在HashSet集合里,它的元素是无序且不可重复的。所以在添加一个元素前,就需要判断集合里是不是已经有了这个元素。

那么该怎么判断呢?

如果用equals方法,那就得遍历整个集合去看一一比较有没有重复,想添加一个元素就需要O(n)的时间复杂度。

如果用hashcode方法,我只需计算出hash值,然后根据hash值去查找是否已经有这个元素了,只需要O(1)的时间复杂度。

所以通常是先执行hashcode方法,如果一样,再执行equals方法。

 

Object类里,equals方法和hashcode方法都是比较对象的内存地址。但是在HashSet里,我们不想根据内存地址去判断是否相等,想根据key值去判断是否相等,所以我们需要重写。

 技术分享图片

 

 技术分享图片

 

 

 

 

接下来会有4个实验:

实验1:两个方法都不重写。

实验2:重写equals方法,不重写hashcode方法。

实验3:重写hashcode方法,不重写equals方法。

实验4:重写两个方法。

 

现在我们有两个人:

Person p1 = new Person("张三");
Person p2 = new Person("张三");

 

按照先执行hashcode方法,如果一样,再执行equals方法”的逻辑,推出以下结果:

实验1:集合里会有两个张三。

实验2:集合里会有两个张三。

实验3:集合里会有两个张三。

实验4:集合里只有1个张三,达到了HashSet不重复的目的。

 

下面做的实验结果和这里的推论一样,不想看可以直接跳到结尾。

 

创建一个Person类:

public class Person {
    private String name;

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

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name;
    }

    //按照实验要求选择性注释
    /*@Override
    public boolean equals(Object obj) {
        if(obj == null) {
            return false;
        }
        if(obj.getClass() != obj.getClass()){
            return false;
        }

        return ((Person)obj).getName() == getName();
    }*/

    //按照实验要求选择性注释
    /*@Override
    public int hashCode() {
        return getName().hashCode();
    }*/
}

 

 

 

再来个测试类:

import  java.lang.*;
import  java.util.HashSet;
import  java.util.Set;

public class Main {

    public static void main(String[] args) {
        Set<Person> set = new HashSet<>();
        Person p1 = new Person("张三");
        Person p2 = new Person("张三");
        set.add(p1);
        set.add(p2);
        System.out.println(set);
    }
}

 

实验1:两个方法都不重写。

结果:

 技术分享图片

实验2:重写equals方法,不重写hashcode方法。

结果:

 技术分享图片

实验3:重写hashcode方法,不重写equals方法。

结果:

 技术分享图片

实验4:重写两个方法。

结果:

 技术分享图片

 

三、总结

Q1:什么场景下,需要重写equals方法和hashcode方法?

A1:判断两个对象是否相等,不是根据对象的内存地址去判断,而是根据key去判断的时候,就需要重写。

比如HashSet集合。

 

Q2:为什么重写equals方法,还必须要重写hashcode方法?

A2:因为HashSetadd方法先执行hashcode方法,如果一样,再执行equals方法。

为了保证性能必须先执行hashcode方法,所以需要重写hashcode方法。

 

Q3:那我只重写hashcode方法,不重写equals方法不可以吗?

A3:不可以哦。一是hashcode方法会有极小概率产生hash冲突(两个对象的hashcode值一样),它只是用来判断该对象在hash表中的位置的,真正判断两个对象是否相等还得用equals方法。

二是不同业务需求不一样,有些需求需要根据姓名或ID啥的key值去判断是否相等,如果不重写equals方法,那就会默认地根据内存去判断。

为什么重写equals方法,还必须要重写hashcode方法

原文:https://www.cnblogs.com/ledphz/p/11748441.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!