聊聊equals 与hashcode

2020-03-29  本文已影响0人  我是陈炜

最近实在是太忙了,许久没有写写技术博客了. 最近发现一个挺有意思的hashcode 与equals 的现象

我们先预设一个条件,假设有一个person.class,我们的hash方法是 如果两个对象的name 和age都相同 那么我们就认为这两个对象 在同一个hashset里面是相同的元素,是需要覆盖的。
但是我发现发现一个挺有趣的现象,如果单单重写对象hashCode方法,hashmap进行插入的时候 并不会生效.

public class EqualsAndHashCodeTest {

    public static void main(String[] args) {
        HashMap<Person,Integer> map = new HashMap<>();
        Person p1 = new Person("a",1);
        Person p2 = new Person("a",1);
        map.put(p1,1);
        map.put(p2,2);
        System.out.println(JSONArray.toJSON(map));

    }

    static class Person {
        private String name;
        private int age;

//        @Override
//        public boolean equals(Object o) {
//            if (this == o) return true;
//            if (!(o instanceof Person)) return false;
//            Person person = (Person) o;
//            return age == person.age &&
//                    Objects.equals(name, person.name);
//        }


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

        @Override
        public int hashCode() {

            return Objects.hash(name, age);
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}
只重写hashcode结果

很明显 单单重写hashcode方法 并不会让我们想要进行覆盖的key 确认,那么 如果单单重写equals呢

只重写equals

只重写equals

上图可以看出 如果只重写equals 也并不会让我们想要进行覆盖的对象进行冲突。

同时重写hashcode 和equals

同时重写hashcode 和equals 的结果

从上图我们可以看到 唯有同时重写hashcode 和equals 且满足我们预设的条件 我们的hashmap才会认为是相同的key。

为什么呢?

为什么会这样 单单重写hashcode 或者equals 并不会让元素的预设规则生效呢?
我们进入hashmap的内部实现

put具体实现
从上图可以看出 put具体就调用了putVal(hash(key), key, value, false, true) 这个方法
hash 方法
hashmap计算对象hash值的时候 会调用对象的hashcode方法。此时 重写hashcode 方法 ,并且person的 age 和name相同的话 得到的hash是相同的

然后我们进入putVal内部

putVal方法
这边可以明显的看到,如果两个对象hash值相同,hashmap还会调用对象的equals方法,如果equals方法也相同,他才会进行覆盖!

问题发生的原因:

hashmap进行put的时候 ,会先比较对象和已有对象的hash值 如果hash值相同,再调用equals方法。
因为obejct.equals 默认比较的是对象的地址值
而object.hashcode()默认生成的是对象的地址值
所以 这两个方法必须都重写 才可以合理使用hashmap 来提高程序性能.

更深一步 为什么java那么设计呢?

上一篇 下一篇

猜你喜欢

热点阅读