欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

equals()方法和hashCode()方法

程序员文章站 2022-06-07 20:07:44
...

equals()和hashCode()方法的关联,以前看明白了,过段时间又忘了,现在记录一下.

先回顾一下

equals()方法

equals()方法是Object类里面的,比较的是两个对象在内存中的首地址,源码如下

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

如果比较我们自己的对象,就需要重写equals()方法.
比如:

    @Override
    public boolean equals(Object o) {
        if(this == o) {
            return true;
        }
        if(!(o instanceof Student)) {
            return false;
        }
        Student temp = (Student)o;
        return this.getName().equals(temp.getName()) && this.getAge() == temp.getAge() && this.getGrade().equals(temp.getGrade());

    }

主意 @Override 注解不能少,因为它会帮助进行我们校验,防止写错.
其实到这一步就行了,两个对象就可以按照我们的需要来比较了.

hashCode()方法

hashCode()方法的返回值是散列表中用到的,也就是HashMap,Set等数据结构里面用到,如果我们创建的类不会在这些数据结构中使用,可以不重写hashCode()方法.

根据 Object 规范,如果两个对象的 equals() 方法返回true,那么这两个对象的 hashCode() 方法返回值一定相同;
如果两个对象的 equals() 方法返回false,那么它们的 hashCode() 方法返回值可以不相同,也可以相同.

两个对象的hashCode如果相同,只能说明它们在散列表数组中的位置相同,具体的比较还是要调用它们的 equals() 方法.

问题1:重写了equals()方法为什么还要重写hashCode()方法

如果重写 equals() 方法的这个类不用作 HashMap 的 key 使用,那么可以不重写 hashCode()方法.
如果需要作为HashMap的key使用,就必须重写.如果不重写,就会发生两个对象的 equals() 方法返回true, 但是它们的 hashCode() 值并不一样的情况,这就违反了Object 规范,直接导致的结果就是HashMap使用错误.
比如:

HashMap<Student, String> map = new HashMap<>();
map.put(new Student("aaa"), "10");
map.get(new Student("aaa"));

如果重写了 equals() 方法,那么第一个Student对象和第二个Student对象应该是相同的,但是结果返回的却是 null, 原因就是它们的 hashCode() 方法没有重写,导致散列值不同,所以返回 null.

问题2:两个对象的hashCode()相同,为什么HashMap还是能取出正确的值.

网上找的一个例子

@Test
    public void test6(){
        System.out.println("ABCDEa123abc".hashCode());  // 165374702
        System.out.println("ABCDFB123abc".hashCode()); //  165374702

        Map<String,String> map = new HashMap<String,String>();
        map.put("ABCDEa123abc","123");
        map.put("ABCDFB123abc","321");

        System.out.println(map.get("ABCDEa123abc"));
        System.out.println(map.get("ABCDFB123abc"));

    }

结果:

165374702
165374702
123
321

两个对象的hashCode相同,只能说明它们所处散列表数组的下标相同,具体的还要看它们本身是否相同,也就是 equals() 方法返回的是 true, 还是 false.

HashMap的 get(Object key)源码如下:

    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

从第5行和第6行能够看到,如果hashCode相同,就会调用它们的equals() 方法.

相关标签: 土味 数据结构