细说为什么重写equals必须要重写hashCode

为什么重写equals必须要重写hashCode

1.一些误区

  1. 重写了equals不重写hashcode并不会报错,只是逻辑上会出错。
  2. 并不是每次重写equals都需要重写hashcode,但推荐都写上。

2.为什么要重写equals

要理解重写hashcode的必要性,我们先来讲讲为什么要重写equals。原因也很简单,默认的equals方法不够看了,需要给它升

级一下。

先看看所有类的祖宗Object类中equals方法的代码,这可以让我们理解为什么要重写equals。

public boolean equals(Object obj) {
    return (this == obj);
}

可以看到,在Object源码里,equals方法就是很简单的用 == 来判断了一下。总所周知, == 对类对象就是判断引用是否相等,

所以默认的equals的逻辑就是:如果需要判断的双方引用了相同的一个对象,那么就是相等的。看起来能满足我们的要求,可

是有的时候如果我们想让不同对象相同内容的两个类也算相等怎么办?比如我们想比较两个字符串对象,虽然它两里面的字

符都是一模一样的,可按照这样的逻辑,还是会判为不同,还好前辈们帮我们在String类里重写了equals方法,我们才能正常

比较。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

3.重写equals的小demo

上面讲了重写equals的原因,我们先写个小demo来铺垫一下。

img

public class EqualsAndHashcode {
    public static void main(String[] args) {
        people people1 = new people();
        people people = new people();

        System.out.println(people.equals(people1));
    }
}

class people{
    private String name;
    private int age;

    public people(){
        name = "李华";
        age = 18;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if (obj==null){
            return false;
        }
        if(getClass() != obj.getClass()){
            return false;
        }
        people other = (people) obj;
        return Objects.equals(name,other.name)
                &&age == other.age;
    }
}

可以看到,对于两个具有相同初始化people对象,equals是可以满足我们要求的。

上面的代码看似没有什么问题,我们想要的结果完美达到,但这只是因为还没遇到会使它犯错的情况:散列表。

4.散列表

先介绍一下散列表放入对象的原理,简单来说就像是给每个位置只能放一个货物的货架摆货:拿到一个货物,先通过

hashCode找到它应该放的位置,如果这个位置是空的,就放上去;如果已经放了货物,就使用equals比较一下放的货物和当

前货物是不是同一个,是同一个就不放了,不是同一个就想办法给它再找一个位置放。

为什么遇到散列表,上面的代码就会出错呢?原因就是因为哈希函数,既然我们想让两个属性一样的类对象视为相等,那么

散列表中也应当如此。

img

那么上面的代码还能满足这个要求吗?

//在main方法加上以下代码
HashSet<test.people> set = new HashSet<>();
set.add(people);
set.add(people1);
System.out.println(set);

结果:

​ [test.people@677327b6, test.people@14ae5a5]

很明显,set 里面有两个元素,虽然我们这两个元素都是一样的,可set不这么认为。这样显然不是我们想看到的结果,他两明明就是相同,怎么还能给它添加进去呢。

这薄荷里

导致这的罪魁祸首大家应该也猜到了,就是哈希函数的锅。先来看看Object中的hashCode是怎么样的:

public native int hashCode();

看不到没关系,我们可以打印这两个people对象的hashCode看看。

System.out.println(people.hashCode());
System.out.println(people1.hashCode());

结果:

​ 1735600054

​ 21685669

这说明在set看来,这两个就是不同的,所以把它们都放进去也合情合理。

到了这里问题也就水落石出了,重写hahsCode的必要性就是因为如果不重写就会导致散列表重复。

5 结论

因为Object类是所有类的祖宗类,所以每个类都应该存在equalshashCode,如果不重写,就是Object类中的实现。当我们

equals进行重写的时候,有可能要放入哈希表也有可能不要,如果需要放入哈希表,那么就需要重写hashCode来保证不会

重复放入。

5 结论

因为Object类是所有类的祖宗类,所以每个类都应该存在equalshashCode,如果不重写,就是Object类中的实现。当我们

equals进行重写的时候,有可能要放入哈希表也有可能不要,如果需要放入哈希表,那么就需要重写hashCode来保证不会

重复放入。

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值