本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看活动链接
一 数据结构
首先就要理解HashMap是什么样的结构,咱们先上图
这个就是HashMap的拉链式存储的数据结构,使用数组加链表
二 key值的产生
key是怎么产生的,如果你之前稍有了解,但是没看过源码,肯定会想到和hashCode方法有关,但是源码中的处理是
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
先说说 这个函数是啥?这东西学名叫做扰动函数,再说说为啥这样干,我们看到这个函数中做了一个hashCode处理,但是还没完,他又做了异或和右移16位的操作,那问题来了,为啥还要这么干?
是由于hashCode产生的key范围太大了[-2147483648, 2147483647],有将近40亿的长度。而后续的处理就是为了缩小这个长度,以及让数据更散列。
三 HashMap的初始化大小
HashMap的初始化大小是多少?相信有一部分的小伙伴会说是16,然后还有很的小伙伴不知道,为啥?因为他们根本没接触过扩容。所以就引出了另一个学名初始化容量,初始化容量一定是2的倍数,扩容后也是2的倍数,因为只有2的倍数-1 才会在二进制中出现0001的数值。
下面提供一个计算扩容后函数的源码,学名 计算阈值大小的方法
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}
扩容还会提到一个学名负载因子,默认的负载因子为0.75,也就是数组塞到3/4就进行扩容。