HashMap存自定义对象为什么要重写 hashcode 和 equals 方法?

HashMap的k放过自定义对象么?

当我们把自定义对象存入HashMap中时,如果不重写hashcode和equals这两个方法,会得不到预期的结果。

class Key{
    private Integer id;

    public Integer getId() {
        return id;
    }

    public Key(Integer id) {
        this.id = id;
    }
}
public class WithoutHashCode{
    public static void main(String[] args){
       //定义两个对象,并声明他俩的id全是1
        Key k1 = new Key(1);
        Key k2 = new Key(1);
        HashMap<Key,String> map = new HashMap<Key,String>();
        map.put(k1, "Key with id is 1");
        System.out.println(map.get(k2));
    }
}

在这里把k1对象作为键put进HashMap,再用k2来get出来并打印。如果没有重写hashcode和equals方法,最终只能得到一个null。
原因很简单,由于我们没有重写hashcode方法,所以在往HashMap中放入k1时依旧调用的是Object类的hashcode方法,返回的是k1对象的内存地址。如果是用map.get(k1)来查找,就能很快得到value值。
但遗憾的是,我们偏偏是用的k2来get。Object的hashcode方法返回的是k2的内存地址,肯定和k1的不相同,换句话说就是他俩的hash值不同,所以不能用k2的hash值拿到k1的value。

重写hashCode和equals方法

class Key{
    private Integer id;

    public Integer getId() {
        return id;
    }

    public Key(Integer id) {
        this.id = id;
    }
    @Override
    public boolean equals(Object o) {
        if (o==null || !(o instanceof Key)){
            return false;
        }else {
            return this.getId().equals(((Key)o).getId());
        }
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}

只重写了hashCode方法后,这里的hashCode方法return的是id的hashCode值。因为我们之前将两个对象的id都设为1,所以他俩的hash值是一样的。
接下来我们再去map.get(k2),会不会拿到value呢?结果还是null。目瞪狗呆有木有?为啥嘞?不是都已经使他俩的hashCode相同了嘛?因为我们只是重写了hashCode方法,并没有重写equals方法啊。不要忘了,HashMap是用链地址法来处理碰撞冲突的。也就是说,某一条链表上的所有的元素的hashCode返回的hash值全是一样的。只重写hashCode方法只能证明k1和k2的hash值相同,当时并不代表他俩就是相等。没有重写equals方法,又是会调用Object类中的equals方法,判断的依旧是两个对象的内存地址!

涨姿势了…

项目中经常会用到HashMap,所以在面试中被问到的频率也是比较高的。如果要在HashMap中的k存放自定义对象,就一定要重写hashcode和equals两个方法,来覆盖掉Object类中的同名方法!

你可能感兴趣的:(Java)