源码:HashMap,Mybatis,Spring 建议看
HashMap: 数组+链表+(1.8之后红黑树)
Object类的hashCode:返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
初始容量:1<<4 即 16.
问 为什么初始容量 是16?
答:java的底层是c语言,C语言底层是汇编语言,汇编再往上就是机器语言,汇编编程使用的就是16进制,因此效率越高。
内部结构
有一个Node类
Node Implement Map.entry{
hash
key
value
next
}
Map.entry
interface Entry<K,V> {
getKey()
setKey()
getValue()
setValue()
比较器,hash等抽象或具体实现的方法
}
当数据传进来时,首先会封装成Node,根据key取hash值,然后 hash(key) &(length()-1) ,存入数据
哈希冲突/碰撞:
1 单向链表:
1.8之前 可以无限挂,1.8之后只能挂7个,第8个的时候转变为红黑树。最大容量为64,达到64再拆分。大于64会扩容。
下挂节点<=6个,会将红黑树再转变为链表
问:为什么是6个时候转变?不是7个呢?
答:7个做准备,多一个是红黑树,少一个链表
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
*/
static final int MIN_TREEIFY_CAPACITY = 64;
2
扩容因子0.75
初始容量16,当存到12时,会扩容成32容量
问:hashMap的扩容怎么操作的?扩容后的元素如何均分的?
答:非常巧妙的处理:
0101 0101 0101 0101 0101 0101 0101 0101 = 每个Node的hash(key)值
0000 0000 0000 0000 0000 0000 0001 0000 = 32 容量
第五位若是0,则不变,若是1,则 当前位置 = 当前位置 +上一个容量
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;