HashMap底层实现原理

HashMap实现原理

1,HashMap实现了Map接口.

2,HashMap的默认初始容量是16
在这里插入图片描述

3. HashMap的最大容量为2的30次方
在这里插入图片描述
4.HashMap的默认负载因子是0.75
在这里插入图片描述

5. 何时链表和红黑树相互转化
在这里插入图片描述
在这里插入图片描述
注意:如果哈希桶中某条链表的个数超过8,并且桶的个数超过64时才会将链表转换为红黑树,否则直接扩容两个条件同时满足才会转换为红黑树。

6. HashMap桶中放置的节点—该节点是一个单链表的结构

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;
    }

    public final K getKey() {
        return key;
    }

    public final V getValue() {
        return value;
    }

    public final String toString() {
        return key + "=" + value;
    }

    // 重写Object类的hashCode()方法
    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }

    // 重写Object类的equals方法
    public final boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
            if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                return true;
        }
        return false;
    }
}

为什么重写equals()和hashCode()方法?

因为,equals()方法只比较两个对象是否相同,相当于==,而不同的对象hashCode()肯定是不同,所以如果我们不是看对象,而只看对象的属性,则要重写这两个方法,如Integer和String他们的equals()方法都是重写过了,都只是比较对象里的内容。
使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()
就是先用哈希函数确定在哪个位置,然后遍历这个位置上对应的链表,直到找到这个Key,然后返回value这里有个地方很关键,那就是如何判断相等,我们看到这里是靠equal函数来判断的,equal函数是所有类都会从Object类处继承的函数,当我们在HashMap中存储我们自己定义的类的时候,默认的equals函数的行为可能不能符合我们的要求,所以需要重写。

equals()和hashCode()的区别和联系

1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
2、如果两个对象不equals,他们的hashcode有可能相等。
3、如果两个对象hashcode相等,他们不一定equals。
4、如果两个对象hashcode不相等,他们一定不equals。
所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!

HashMap的哈希函数

/*
1. key如果为空,返回的是0号桶
2. key如果不为空,返回该key所对应的哈希码,从该位置可以看出,如果key是自定义类型,必须要重写Object类
的hashCode方法
3. 高16bit不变,低16bit和高16bit做了一个异或,主要用于当hashmap 数组比较小的时候所有bit都参与运算了
目的是减少碰撞
4. 获取到哈希地址后,计算桶号的方式为:index = (table.length - 1) & hash
5. 通过除留余数法方式获取桶号,因为Hash表的大小始终为2的n次幂,因此可以将取模转为位运算操作,提高效
率,这也就是为什么要按照2倍方式扩容的一个原因
key&(table.length-1) 二进制 index key%(table.length-1) index
4&15 100&1111 100 4%15 4
13&15 1101&1111 1101 13%15 13
19&15 10011&1111 11 19%15 4
通过上述方式可知,实际上hashcode的很多位是用不上的,因此在HashMap的hash函数中,才使用了移位运算,只
取了hashcode的前16位来做映射。2^15=65536 已经是很大的数字了,另一方面&操作比取模效率更高
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

扩容机制

在这里插入图片描述
每次都是将cap扩展到大于cap最近的2的n次幂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值