重写equals方法需同时重写hashCode方法

118 阅读3分钟

hashCode()介绍

hashCode()的作用是获取哈希码,也称为散列码;返回一个int整数。这个哈希码的作用就是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数.

散列表存储的是键值对(key-value).它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利⽤到了散列码!

hashCode()的作用

当把对象加入HashSet时,HashSet会首先计算对象的hashCode来判断对象加入的位置,同时也会与该位置其它已经加入的对象的hashCode值作比较,如果没有相符的hashCode,则表示要加入的对象没有重复出现。但是如果发现相同的hashCode值的对象,这时就会调用equals()方法来检查hashCode相等的对象是否真的相同。如果两个真的相同,HashSet就不会将其加入操作。如果不同,就会重新排列到其它位置。

所以,hashCode()的作用就是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定在哈希表中的索引位置。

hashCode()equals()相关规定
  1. 在java应用程序执行期间,如果在equals方法比较中所用的信息没有被修改,那么在同一个对象上多次调用hashCode方法时必须一致地返回相同的整数。如果多次执行同一个应用时,不要求该整数必须相同
  2. 如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。
  3. 如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。

Object类中,hashCode方法是通过Object对象的地址计算出来的。因为Object对象只与自身相等,所以同一个对象的地址总是相等的,计算的哈希码也必然相等。对于不同的对象,地址不同,所获得的哈希码自然也不会相等。如果重写了equals()方法,但是没有重写hashCode方法,违反了第二条规定。

示例代码

package equals.src;

import java.util.HashMap;
import java.util.Map;

public class App {
    public static void main(String[] args) {
        Map<String, Value> map1 = new HashMap<String, Value>();
        String s1 = new String("key");
        String s2 = new String("key");
        Value value = new Value(2);
        map1.put(s1, value);    // 把s1和value放到hashMap
        System.out.println("s1.equals(s2):" + s1.equals(s2)); // s1.equals(s2):true
        System.out.println("map1.get(s1):" + map1.get(s1)); // map1.get(s1):类Value的值-->2
        System.out.println("map1.get(s2):" + map1.get(s2)); // map1.get(s2):类Value的值-->2

        Map<Key, Value> map2 = new HashMap<Key, Value>();
        Key k1 = new Key("A");
        Key k2 = new Key("A");
        map2.put(k1, value);
        System.out.println("k1.equals(k2):" + k1.equals(k2));   // k1.equals(k2):true
        System.out.println("map2.get(k1):" + map2.get(k1));     // map2.get(k1):类Value的值-->2
        System.out.println("map2.get(k2):" + map2.get(k2));     // map2.get(k2):null
    }

    static class Key {
        private String k;

        public Key(String key) {
            this.k = key;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Key) {
                Key key = (Key) obj;
                return k.equals(key.k);
            }
            return false;
        }
    }

    static class Value {
        private int v;

        public Value(int v) {
            this.v = v;
        }

        @Override
        public String toString() {
            return "类Value的值-->" + v;
        }
    }

}

上述代码中:Key这个类重写了equals()方法,但是没有重写hashCode()方法。String类重写了equals方法和hashCode方法。

所以,map1可以得到s1和s2的值,因为String类比较的是内容,它的hashCode也是根据内容获取的哈希码。

map2只能获取k1的值,不能获取到k2的值。这是为什么??因为Key只重写了equals方法,并没有重写hashCode方法。这样的话,equals方法比较的是内容,所以打印为true。但是hashCode没有被重写,所以就调用超类ObjecthashCode方法,而这个方法返回的是一个地址(是根据地址来获取hashcode的)。而k1和k2又是不同的对象,它们的地址肯定不同,所以获得的hashcode也不同。因为k2返回为null