博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解HashMap底层实现原理
阅读量:5348 次
发布时间:2019-06-15

本文共 3699 字,大约阅读时间需要 12 分钟。

一、HashMap (JDK8)put(K key, V value)底层实现

1. 首先判断这个hashmap是否为空,为空就初始化一个hashmap

2. 根据key 计算hashcode()值,和数组长度-1 进行&(等价于求余), 得到bucket的位置

3. 得到位置后 判断该处的值是否为空 如果为空 直接插入

4. 如果不为空,判断数组后面链接的是否是一棵树,是树就将其put到这颗树中。

5. 不是树,先挂在链表后面,然后判断链表大小是否大于8,大于8就要把链表转换成树

源码:

 

1 public V put(K key, V value) { 2         return putVal(hash(key), key, value, false, true); 3     } 4      /** 5      * Implements Map.put and related methods 6      * 7      * @param hash hash for key 8      * @param key the key 9      * @param value the value to put10      * @param onlyIfAbsent if true, don't change existing value11      * @param evict if false, the table is in creation mode.12      * @return previous value, or null if none13      */14 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,15                    boolean evict) {16         Node
[] tab; 17 Node
p; 18 int n, i;19 if ((tab = table) == null || (n = tab.length) == 0)20 n = (tab = resize()).length;21 /*如果table的在(n-1)&hash的值是空,就新建一个节点插入在该位置*/22 if ((p = tab[i = (n - 1) & hash]) == null)//&相当于取余23 tab[i] = newNode(hash, key, value, null);24 /*表示有冲突,开始处理冲突*/25 else {26 Node
e; 27 K k;28 /*检查第一个Node,p是不是要找的值*/29 if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))30 e = p;31 else if (p instanceof TreeNode)//数组后面是否为树,如果是树则将其put到树中32 e = ((TreeNode
)p).putTreeVal(this, tab, hash, key, value)33 else {
//否则挂在链表后面34 for (int binCount = 0; ; ++binCount) {35 /*指针为空就挂在后面*/36 if ((e = p.next) == null) {37 p.next = newNode(hash, key, value, null);38 //如果冲突的节点数已经达到8个,看是否需要改变冲突节点的存储结构,             39             //treeifyBin首先判断当前hashMap的长度,如果不足64,只进行40 //resize,扩容table,如果达到64,那么将冲突的存储结构为红黑树41 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st42 treeifyBin(tab, hash);43 break;44 }45 /*如果有相同的key值就结束遍历*/46 if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))47 break;48 p = e;49 }50 }51 /*就是链表上有相同的key值*/52 if (e != null) { // existing mapping for key,就是key的Value存在53 V oldValue = e.value;54 if (!onlyIfAbsent || oldValue == null)55 e.value = value;56 afterNodeAccess(e);57 return oldValue;//返回存在的Value值58 }59 }60 ++modCount;61 /*如果当前大小大于门限,门限原本是初始容量*0.75*/62 if (++size > threshold)63 resize();//扩容两倍64 afterNodeInsertion(evict);65 return null;66 }

二、扩容

hashmap 默认大小16,每次扩大两倍(增加一倍),加载因子默认是0.75,当 hashmap容量大于 数组长度 * 加载因子的时候就会扩容,也就是初始达到12 的时候就会扩容

扩容时先重建一个2倍长度的数组,然后重新 hash

加载因子表示数组填充的程度,加载因子越大填充的越满,空间利用率越高,但冲突越大,加载因子越小,空间利用率越低,但冲突小,一般平衡在0.75

为什么每次数组的大小都是2的次幂?

1.在计算哈希桶下标的时候hash值和 数组长度减一按位与,数组长度是2的倍数减一二进制表示都是1,速度快;

2. hash & (array.length-1)相当于对array.length-1 取模运算,也就是 % 运算,&效率比%高;

3.数组长度是2的次幂,不同key求的hash值相同几率很小,冲突小,查询快

 三、HashMap和HashTable的区别

1. hashmap 的 key  可以为 null,hashtable不行,为空时,hashcode默认为0。

2. hashtable是线程安全的,方法前面都有 synchronized 关键字。

3. hashtable继承Dictionary 类,hashmap继承 AbstractMap类,但都实现了 Map、Cloneable、Serializable接口

四、如何保证HashMap线程安全

1. 使用ConcurrentHashMap

2. Collections.synchronizedMap(new HashMap<String, Integer>());

转载于:https://www.cnblogs.com/yumingxing/p/9493927.html

你可能感兴趣的文章
php学习日志(5)-解决Windows Live Writer错误:WindowsLive.Writer.CoreServices.HttpRequestHelper的类型初始值设定发生异常...
查看>>
HOUR 14 Calling Advanced Functions
查看>>
hadoop集群搭建实践
查看>>
vue-cli 3.0 学习笔记
查看>>
军哥lnmp环境安装phalcon
查看>>
高效的从千万数据取随机行
查看>>
小组项目
查看>>
drupal 8——打补丁(patch)
查看>>
9.26表单验证和事件、正则表达式
查看>>
acm课程练习2--1003
查看>>
织梦dede:arclist输出取消换行符
查看>>
Silverlight 4以下版本模拟鼠标双击事件
查看>>
[PA 2014]Bohater
查看>>
HDU 6017 Girls Love 233(多态继承DP)
查看>>
HDU 1260 Tickets
查看>>
【leetcode❤python】206. Reverse Linked List
查看>>
内存池技术畅想
查看>>
EJB远程接口调用
查看>>
HNOI 排队
查看>>
PDO预处理语句规避SQL注入攻击
查看>>