zhujiangtaotaise 2019-12-22
简介
HashMap采用key/value存储结构,每个key对应唯一的value,查询和修改的速度都很快,能达到O(1)的平均时间复杂度。它是非线程安全的,且不保证元素存储的顺序;
继承体系
分析:
存储结构
在Java中,HashMap的实现采用了(数组 + 链表 + 红黑树)的复杂结构,数组的一个元素又称作桶。
在添加元素时,会根据hash值算出元素在数组中的位置,如果该位置没有元素,则直接把元素放置在此处,如果该位置有元素了,则把元素以链表的形式放置在链表的尾部。
当一个链表的元素个数达到一定的数量(且数组的长度达到一定的长度)后,则把链表转化为红黑树,从而提高效率。
数组的查询效率为O(1),链表的查询效率是O(k),红黑树的查询效率是O(log k),k为桶中的元素个数,所以当元素数量非常多的时候,转化为红黑树能极大地提高效率。
源码分析
/** * 默认的初始容量为16 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; /** * 最大的容量为2的30次方 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 默认的装载因子 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 当一个桶中的元素个数大于等于8时进行树化 */ static final int TREEIFY_THRESHOLD = 8; /** * 当一个桶中的元素个数小于等于6时把树转化为链表 */ static final int UNTREEIFY_THRESHOLD = 6; /** * 当桶的个数达到64的时候才进行树化 */ static final int MIN_TREEIFY_CAPACITY = 64; /** * 数组,又叫作桶(bucket) */ transient Node<K,V>[] table; /** * 作为entrySet()的缓存 */ transient Set<Map.Entry<K,V>> entrySet; /** * 元素的数量 */ transient int size; /** * 修改次数,用于在迭代的时候执行快速失败策略 */ transient int modCount; /** * 当桶的使用数量达到多少时进行扩容,threshold = capacity * loadFactor */ int threshold; /** * 装载因子 */ final float loadFactor;
(1)容量
容量为数组的长度,亦即桶的个数,默认为16,最大为2的30次方,当容量达到64时才可以树化。
(2)装载因子
装载因子用来计算容量达到多少时才进行扩容,默认装载因子为0.75。
(3)树化
树化,当容量达到64且链表的长度达到8时进行树化,当链表的长度小于6时反树化。