java为什么重写equals时都推荐重写hashCode

很多人在重写equals时,都会看到网上一般推荐同时重写hashCode,为什么呢?一开始我以为equals中比较的是hashCode,查了下源码发现并不是这么回事,那么到底为什么会有这么一个推荐呢?

hashCode值代表的含义

首先,我们要知道hashcode值不是内存地址,hashcode值是对内存地址进行一些算法操作后得到的值,可能多个内存地址对应一个hashcode值,比如整数的取模(16%9=7,25%9=7,最后16和25具有相同的hashcode值),那为什么要对内存地址进行一些算法操作呢?这是因为到像hashMap之类的数据结构中添加数据,而hashmap中已经存有非常多的数据时,如果没有hashcode值,我们就得一个个遍历所有的数据看是否含有相同的数据,这样的效率特别低下,但当你使用hashcode值比较的话,你只需比较具有相同hashcode值的数据即可,这就使得效率大大提高;

equals()和hashCode()的区别

上面我们知道一个hashcode值可能对应多个内存地址。也就是说内存地址不同,但hash值可能相同,但hash值不同,内存地址一定不同。所以比较对象时,先通过hashCode()比较,如果不等则两对象一定不同,如果相等再通过equals()比较,如果相等则两对象相同,如果不等则两对象不同。

重写

而String重写了equals同时重写了hashCode,重写hashCode代码如下:
在这里插入图片描述
通过源码可以看到String类的hashCode是通过对象的值来确定的,而String类中equals比较的就是值,而不是地址。这就保证了String重写equals时equals和hashCode的一致性。
我们来看一段代码:

public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        o1 = "sss";
        o2 = "sss";
        System.out.println(o1.equals(o2));
        System.out.println("o1.hashCode():" + o1.hashCode());
        System.out.println("o2.hashCode():" + o2.hashCode());
    }

结果为:
在这里插入图片描述
我们可以看到当equals相同时,对应的hashCode也是一样的,这就是equals和hashCode的一致性。为什么会存在这种一致性呢?那是因为像hashMap,hashSet这些集合框架,当你重写了equals方法而没有重写hashCode()时,可能会出现equals相同,而hashCode却是不同的,然后在这些集合框架对hashCode比较时,显示false,这和我们的预期存在差入。

重写equals而不重写hashCode

 @Override
    public boolean equals (Object o) {
        if (o instanceof Student) {
            Student s = (Student) o;
            if (this.sName.equals(s.sName)) return true;
            else return false;
        }
        return false;
    }
public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        s1.setsName("sss");
        s2.setsName("sss");
        System.out.println(s1.equals(s2));
        System.out.println("s1.hashCode():" + s1.hashCode());
        System.out.println("s2.hashCode():" + s2.hashCode());
    }

结果为:
在这里插入图片描述
从结果看没重写hashCode()时,本来我们是想两个age相同的hashCode应该是一样,可hashCode是不同的地址。而如果是hashMap或hashSet这些集合框架时,就会产生了一些错误。像hashSet去重的话,我们是想将age相同的去重,但是从上面我们知道两个age相同,但hashCode不同,而去重是对hashCode的比较,最后也就达不到我们想要的去重效果。

即重写equals又重写hashCode

@Override
    public int hashCode () {
        return this.sName.hashCode();
    }
    @Override
    public boolean equals (Object o) {
        if (o instanceof Student) {
            Student s = (Student) o;
            if (this.sName.equals(s.sName)) return true;
            else return false;
        }
        return false;
    }
public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        s1.setsName("sss");
        s2.setsName("sss");
        System.out.println(s1.equals(s2));
        System.out.println("s1.hashCode():" + s1.hashCode());
        System.out.println("s2.hashCode():" + s2.hashCode());
    }

结果为:
在这里插入图片描述
我们可以看到equals返回true,而且hashCode的地址也是一样的,这就符合之前所说的equals和hashCode的一致性。完美。这个时候你就没必要担心一些比较会出现问题了。所以说当你重写equals时,最好将hashCode也跟着一起重写。当然如果你非常确定你不会使用到hashCode比较,也是可以不重写hashCode的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值