jdk8源码中hashmap的简单分析

你能说一说为什么实现equals方法的时候需要实现hashcode吗,读过hashmap的源码吗

面试的时候面试官可能会问你hashmap的实现原理,在这里我以一种简单而形象的表达说一下hashmap的主要实现。

首先,让我们联想一下hashmap的结构,这里可以先给一张结构图

可以看到hashmap里面的主要存储结构是table数组,数组里面存放的可以是单一的节点,也可以是链表节点。

数组table的定义如下

transient Node<K,V>[] table;

节点定义如下

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        /**
        * 省略一些方法
        */
}

每个table存放的都是这样结构的节点,现在的问题是如何存放这样的节点呢,这就需要根据key的hashcode值来决定摆放的位置了,hashcode的值计算代码如下

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

看到了把,这里就需要调用每个key的hashCode方法。

然后得到hash值之后,就需要put进table里,这里就需要判断了,到底对应table哪个下标呢,这里源码给出的计算如下

p = tab[i = (n - 1) & hash]

然后判断这里的p如果为null,说明table数组当前下标没有节点,可以安心放入,但是如果发生了hash碰撞了,即里面已经存放了一个节点怎么办呢,我们这时候才需要判断已经存在的节点的key的值和将要放入的节点的key值是否相等,源码有这样的判断

(k = p.key) == key || (key != null && key.equals(k)))

ok,这时候如果key相等了,就直接进行值的覆盖,既新值盖旧值,源码的赋值如下

if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }

e.value = value,就是对节点赋上了新值了。

如果key不相等的话,那就在节点后面新建一个节点,形成一个链表。注意一下当链表长度大于默认值8的时候,会自动转化为红黑树,来缩短查询时间。

所以这里hashmap的原理大概清楚这几点就差不多了,可以看出equals方法只是在比较hash发现有冲突后才调用的,这样能大大缩短比较次数,加快查找速度。

hashmap在查找性能上还是相当高的哈。

最后解释一下为什么需要重写hashcode方法

  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 两个对象相等,对两个对象分别调用equals方法都返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值