HashMap底层实现原理

HashMap简介

        HashMap底层是哈希表/散列表的数据结构,哈希表是数组和单向链表的结合体。数组查询效率高,随机增删效率低;单向链表查询效率低,随机增删效率高。哈希表将这两种数据结构融合在一起,充分 发挥它们各自的优点。

HashMap底层源码

public class HashMap<K, V> {
    Node<K, V>[] table;
    static class Node<K,V> {
        final int hash;//哈希值(哈希值是key的hashCode()的执行结果,哈希值通过哈希算法可以转换为数组的下标)
        final K key;//map集合中的key
        V value;//map集合中的value
        Node<K, V> next;//下一个节点的内存地址
    }
    ······
}

在这里插入图片描述

HashMap的put()方法

        先将key和value封装到Node对象中,底层调用key的hash(key)方法算出hash值,然后通过hash算法将hash值转换为数组下标。如果下标位置上没有元素就把Node添加到该位置上;如果下标位置上有链表,此时会拿着当前Node中的key与链表中的每一个Node中的key进行equals()比对,如果所有的比对结果都为false,那么当前Node添加到链表的末尾(jdk8以前是头部),如果其中有一个比对结果返回了true,那么会将链表中的这个Node中的vaule将会被覆盖。
        jdk8以后,当单项链表上的元素达到8个时,会将单向链表转换为红黑树。当红黑树上的元素少于6个时,会将红黑树转换为单向链表。这种方式也是为了提高检索效率。

HashMap的get(key)方法

        先调用key的hash(key)方法得出hash值,然后通过hash算法将hash转换为数组下标,通过数组下标快速定位到数组的某个位置上,如果这个位置上什么也没有返回null。如果这个位置上有单向链表,会拿着这个key和单向链表中每个Node进行equals()比对。如果所有比对结果为false,那么get()结果返回null;如果其中有一次比对结果返回true,那么get()结果将返回这个Node的value。

hash算法

        在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。

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

        获得hash值后,用数组的长度-1与(&)该hash值得到key在数组中对应的位置。

HashMap扩容

        HashMap的默认初始化容量为16,默认加载因子为0.75(当HashMap容量达到75%时底层数组开始扩容,扩容后的容量为原容量的2倍)HashMap的初始化容量必须是2的次幂,这也是官方推荐的,这也是达到散列均匀和提高存取效率所必需的的
        默认情况下,数组大小为16,那么当hashmap中元素个数超过16×0.75=12的时候,就把数组的大小扩展为2×16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。

为什么哈希表的查询效率和随机增删效率都很高?

1、查询不需要全部扫描,只需要部分扫描。
2、增删是在链表上完成

HashMap的key部分特点

无序、不可重复

为什么无序?

不一定会挂到哪一个单向链表上 。

如何保证不可重复?

equals()方法保证了不可重复,如果key重复了value会覆盖。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值