Java中的hashCode方法以及对HashMap的影响

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xyh930929/article/details/74739068

一、hashCode基本介绍

hashCode方法是Object类中方法,Java中的每一个对象都有该方法,该方法返回的是一个整数值。该方法是一个本地方法。hashCode返回的默认值是该对象在JVM中的地址值的十进制形式。

public native int hashCode();

在jdk源码中关于hashCode方法的一些约定都写在了方法注释上。翻译结果如下图:

总结为以下3点:

  • 如果一个对象的equals方法没有被重写,在对该对象多次调用hashCode方法时,必须一致地返回相同的整数。
  • 如果两个对象用equals比较相等,那么这两个对的hashCode也必须相同。
  • 如果两个对象用equals比较不相等,不要求hashCode方法必须相同。

二、jdk中涉及到hashCode的源码

2.1 Object类中的toString方法

toString方法返回的是对象的class全名+“@”+hashCode的十六进制。

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

2.2 HashMap类的put(K,V)方法

  • HashMap的数据结构是一个散列,关于HashMap的介绍可以参考这篇文章

  • 下面是put方法的源码:HashMap方法是不允许key重复的,在向HashMap中put元素时,源码中调用了putVal方法,但是调用该方法时,并没有直接将key传给该方法,而是将hash(key)传给了putVal方法。接下来的判断key是否重复、以及为key寻址的过程指的都是hash(key),而不是一开始传入的key值。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
  • 上面提到的hash(key)方法源码如下:根据hash函数的源码可以看到,调用HashMap方法put方法时,真正使用的key都不是原始的key值,而是调用了key值的hashCode方法进行计算得到的新值。
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

2.2 HashMap类的get(K)方法

  • get(K)方法在根据key获取元素时,实际使用的key也是hash(key)方法返回的值。源码如下:
public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

三、不按照jdk的约定的后果

3.1 不按照约定对toString方法的影响

  • 该方法虽然调用了hashCode方法,但是hashCode是否重写对该方法影响不大,因为大多数的需要用到toString方法的封装类都对toString方法进行了重写。例如String、Integer等。

3.2 不按照约定对HashMap的put和get的影响

  • 通过前面分析HashMap的put方法和get方法,可以知道:put方法在添加元素之前get方法在获取元素之前是用的都不是实际传入的key,而是hash(key)方法的返回值,而hash(key)方法中调用了key的hashCode方法。

  • 根据HashMap的底层实现原理:put方法在添加元素相当于寻址(为元素寻找合适的位置)和get方法在获取元素相当于根据元素的地址获取元素的值那么如果你在put(K,V)元素时和get(K)元素时K的hashCode()方法返回值不一致,就会导致get(K)获取元素时,找不到元素真正的位置,导致返回值是null。

举例如下:重写一个Demo类的hashCode方法。

public class Demo {

    @Override
    public int hashCode() {
        return (int)(Math.random()*1000);//让每一次调用hashCode方法的返回值都是一个随机数。
    }

    public static void main(String[] args) {
        Map map = new HashMap();

        Demo d = new Demo();

        map.put(d,1);

        System.out.println(map.get(d));//结果是null,如果不重写可以获取到value值也就是1.
    }

}

猜你喜欢

转载自blog.csdn.net/xyh930929/article/details/74739068
今日推荐