一、简介
HashMap
是基于Map
接口的具体实现类,可以存储null
键和null
值。
相比于Hashtable
,HashMap
是线程不安全的,没有同步操作,效率高。
二、键唯一性
HashMap
中的泛型是<K,V>
格式的,在具体的实现中,HashMap是可以保证键的唯一性的,但是存在特殊情况。
- 如果是基本数据类型或者内置数据类型的包装类,例如:
Integer
、String
等,可以保证键的唯一性。如果添加相同的键的数据多次,则会按照添加顺序覆盖最先添加的数据。 - 如果是引用数据,如
Object
类,则不能保证键的唯一性,即不能保证去重效果。想要保证去重效果,则需要在定义类的时候重写hashCode()
方法和equals()
方法
三、结构
在jdk 8中,HashMap是由数组+链表+红黑树共同实现的。
四、扩容
- 扩容长度:默认数组的长度是16,并且发生扩容的时候,长度都为之前的
2倍
。也就是说,长度只可能为16、32、64…… - 加载因子:扩容发生的阈值,因为扩容是在容量用完之前就需要进行的。如果等到用完之后需要添加大量数据,这个时候还没来得及扩容就会发生容量不够用的情况。
- 目前的阈值参数为0.75。如果按照初始值容量计算,当占用容量空间达到
16*0.75=12
时,就会发生扩容,扩容之后的容量变为16*2=32
;后续情况依此类推。
- 目前的阈值参数为0.75。如果按照初始值容量计算,当占用容量空间达到
- 转换为红黑树:当哈希表上同一位置上的数据过多,即单一
Node
上的数据量过多,该Node
上的数据默认会使用链表的结构进行排列,数据过多就会造成效率低下,JDK 8中对此情况做了优化:数据量到一定程度的时候,将链表形式的数据转换为红黑树的结构。- 转换条件:如果一条链表中元素的个数达到
TREEIFY_THRESHOLD
(默认是8),并且table的长度大于MIN_TREEIFY_CAPACITY
(默认是64),就会将链表转为红黑树来提高效率(JDK 8)。 - 如果一条链表中元素的个数达到
TREEIFY_THRESHOLD
(默认是8),并且table的长度小于MIN_TREEIFY_CAPACITY
(默认是64),那么链表并不会转为红黑树,而是将数组扩大至原来的2倍(并且是每添加一 次就扩大2倍),直到数组长度达到64(此时链表就可以转为红黑树了),也就达到了效率最高。- 前者满足,后者不满足:则链表中每添加一个数据,数组长度扩大为原来的两倍,直至table的长度达到
MIN_TREEIFY_CAPACITY
(默认是64),转换为红黑树。 - 前者不满足,后者满足:链表中数据长度不足够转换为红黑树,两者效率差距不大,直至链表中数据增加至
TREEIFY_THRESHOLD
(默认是8),转换为红黑树。
- 前者满足,后者不满足:则链表中每添加一个数据,数组长度扩大为原来的两倍,直至table的长度达到
- 转换条件:如果一条链表中元素的个数达到
五、TreeMap
TreeMap
是基于红黑树(Red-Black tree)的 NavigableMap
的实现类。
该映射根据其键的自然顺序进行排序, 或者根据创建映射时提供的 Comparator
进行排序,具体取决于使用的构造方法。
实现类中不包含同步代码块,线程非安全,效率高。