一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
HashMap 源码分析-基础结构
HashMap 源码比较多,相关的面试题也比较多,但是这些基本也都是考察源码的相关问题。
底层结构
底层数据结构主要是:数组 + 链表 + 红黑树。
特点:当链表的长度大于等于 8 时,链表会转化成红黑树;当红黑树大小小于等于 6 时,红黑树会转化成链表
从 HashMap 的类注释中可获得的信息:
- 允许 null 值存在
- 线程不安全
- load factor 表示扩容因子,默认值为 0.75
- 不扩容的条件:数组容量 > 需要的数组大小 /load factor;反之,不满足这个条件就会进行扩容
- 如果需要插入的数据量比较大的话,建议在new HashMao时就先设置成足够的大小,为了避免在插入过程中不断的进行扩容,耗费不必要的性能
- Collections中的synchronizedMap 也可以实现线程安全,其主要实现方法是在每个方法上都加上了synchronized 锁
- 迭代过程中,如果 HashMap 的结构被修改,会快速失败。(类似ArrayList,用modCount记录修改次数)
源码:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
private static final long serialVersionUID = 362498820763181265L;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
.........
transient Node<K,V>[] table;
transient Set<Map.Entry<K,V>> entrySet;
transient int size;
transient int modCount;
int threshold;
.......
static class Node<K,V> implements Map.Entry<K,V> {
..........
}
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
..........
}
..........
-
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;初始容量为 16(2的4次方) -
static final int MAXIMUM_CAPACITY = 1 << 30;HashMap最大容量为2的30次方 -
static final float DEFAULT_LOAD_FACTOR = 0.75f;扩容(负载)因子默认值为0.75 -
static final int TREEIFY_THRESHOLD = 8;当链表长度大于等于8时,链表会转换成红黑树 -
static final int UNTREEIFY_THRESHOLD = 6;当大小小于等于6时,红黑树转换为链表 -
static final int MIN_TREEIFY_CAPACITY = 64;约定当数组容量大于 64 时,链表达到转换成红黑树的条件 -
transient int modCount;记录迭代过程中 HashMap 是否发生修改 -
transient int size;记录HashMap的实际大小 -
transient Node<K,V>[] table;存放数据的数组 -
int threshold;扩容的条件 -
static class Node<K,V> implements Map.Entry<K,V>链表的节点 -
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {红黑树的节点