为什么重写了equals()还要重写hashCode()

目录

存数据的源码

不重写hashCode方法会发生什么

我们如果不重写equals会发生什么?

为什么要重写equals方法


 

存数据的源码


当传入的K的hash值table表当前位置的值得hash相同 并且 传入的K与当前 K 是同一个对象时

或者

传入的K不是null 并且 K与当前Key 的equals为true

那么 将e指向p所指向的 也就是不将传入的那个值加入到hashMap中

if (p.hash == hash && 
        ((k = p.key) == key || (key != null && key.equals(k)))) 
        e = p;

public class Main {
    public static void main(String[] args) {
   // write your code here
        P p1 = new P("java", 20);
        P p2 = new P("java", 20);

        HashMap<P, String> pStringHashMap = new HashMap<>();
        HashMap<String, P> stringPHashMap = new HashMap<>();
        pStringHashMap.put(p1,"java1");
        pStringHashMap.put(p2,"java2");

        System.out.println("<P,String>"+pStringHashMap);
        stringPHashMap.put("java1",p1);
        stringPHashMap.put("java2",p2);
        System.out.println();
        System.out.println();
        System.out.println("<String,P>"+stringPHashMap);
    }
}
class P{
    private String name;
    private int age;
    public P(String name, int age) {this.name = name;this.age = age;}
    @Override
    public String toString() {return "P{" + "name='" + name + '\'' + ", age=" + age + '}';}
}

p1 p2 是两个内容相同的不同对象

P没有重写equals方法 其运行结果为

ec591344be7f473aaa012c081b2674fd.png

由此看出,没有重写equals方法 会将相同的K存到hashmap中,但这是hashMap不允许的

再来看hashMap的put源码,

if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))

        e = p;

不重写hashCode方法会发生什么

不同的对象hash值不确定相同不相同  可能相同

p1,p2(P p1 = new P("java", 20); P p2 = new P("java", 20);)是不同对象,

Hash值有可能不相同有可能相同,所以(p.hash == hash为false或true

由于不是同一个对象,并且没有重写equals方法,所以((k = p.key) == key  一定为false|| (key != null && key.equals(k)))一定为false,整体条件值就是false,

所以put中的if判断条件为false. 也就是说,跳过了值覆盖

这时候问题就来了,值一样的两个不同对象,这是不可以重复加到map中的,但是这样做却跳过了覆盖,结果是还是加入了map中,

那我们就重写hashcode方法,让具有相同值的不同对象的hash值根据对象中的字段产生,使他们的hash相同,

根据对象的 字段属性 作为重写hash的依据,相同字段产生的hash肯定是相同的。

这样子是不是就解决问题了呢,显然是不行的

虽然我们重写了hash,保证了(p.hash==hash 为true)确保了值相同的不同对象的hash值也相同,但是覆盖的条件是 hash相同并且equals也相同.   就算第一个条件复合了,那么第二个条件是用来判断对象是不是  相同值 的!  两个条件一起符合,才会覆盖!

我们如果不重写equals会发生什么?


f12f1623531d44a897b92c23ce1b7ff0.png

虽然我们保证了不会因为hash带来问题 但是如果不重写equals 默认使用的是Obj的equals方法 (不难看出 只是 比较两个对象在内存中的地址是否相同)

p1,p2(P p1 = new P("java", 20); P p2 = new P("java", 20);)是不同的对象,所以返回的一定是false。

这时候,我们重写了hash,保证了hash一定返回的是ture,但是,equals却还是返回的false

也就是说:整体还是返回false 依旧会发生将相同值的对象存储到map中的问题,

如果我们将equals方法也重写呢?

将equals方法重写,让它逐个判断对象中的字段值

为什么要重写equals方法

将equals重写之后,使它也会去判断对象中存储的值,如果相同,返回true反之返回false

这样一来,我们存储的是 相同值的不同对象 因为重写的hashCode是根据对象中的字段来重写的,这时就会保证这样的对象的hash一定会相同(true)


因为重写了equals方法,我们逐个比较了对象中存储的值,发现都是相同的,那么

equals方法也会返回true

也重写了

这时整体条件为true,就会将一个重复值覆盖,从而不会产生相同的值


综上可知,无论单一重写那个方法都是没有办法限制具有相同值得不同对象存入map中的,所以两个方法一定要同时重写

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值