Map散列表

HashMap与LinkedHashMap

这2个Map是我们最常见的map。LinkedHashMap内部使用了双向链表来维护元素的顺序,所以遍历的时候取出来的元素顺序和插入顺序一致,而HashMap就不是。

hashmap-1

linkedhashmap-1

可以看到LinkedHashMap继承自HashMap,只不过它内部保存了一个双向链表来维护顺序。下图中,指针head、tail就是链表的首尾节点!

map-3

网上关于hashmap分析地比较好的文章:hashmap1.7与1.8

JDK1.8的HashMap

因为现在都用1.8了,所以还是以1.8的为准。

关于HashMap以及ConcurrentHashMap,网上的分析已经很透彻了。这里就提几个点吧。

1.关于容量,HashMap的容量最小是16,每次扩容都是2的倍数,这是有原因的。也就是说:

new HashMap<>(14)生成的map容量是16,new HashMap<>(24)生成的map容量是32。

2.负载因子loadFactor是0.75,也就是4分之3。当放入map的元素达到capacity * loadFactor时,就要进行扩容操作。假设我们初始化的容量是16,那么放入第12个元素时,就会进行扩容操作,变成32容量。

3.散列表的结构,我们需要提及一下元素put的时候如何决定放入数组的哪个格子里?如下图,索引值=(n-1) & hash,n是map的大小。当map大小为16时,那么n-1的二进制就是000...001111(前面都为0,末4位为1);那么与hash值相与,结果就=000...00xxxx,即后4位由hash值所决定,hash值原来的后4位是什么就是什么,这样最后的结果就处于0~15之间了,正好对应大小为16的数组的索引范围。

map-1

4.因为是1.8的HashMap,当链表的长度达到8个时,就会转化为红黑树进行存储,这样搜索效率就会达到Olog~2~N。

5.在get查找元素的时候,当计算好数组下标后,判断如果该节点是Node(普通节点),就遍历查找;如果是TreeNode,就使用红黑树的方式查找。


HashTable

table-1

HashTable又是一个远古的类。HashTable与HashMap就如同Vector与ArrayList,这么一说你应该明白了。HashTable也是使用synchronized修饰了其操作方法,锁的粒度极大,不推荐使用!

TreeMap

TreeMap的想法是,在遍历元素的时候,之前的HashMap取出的元素是无序的,LinkedHashMap取出的元素是按照插入顺序的,那我还需要按照自己定义的元素顺序来保存元素,这样取出元素的时候就符合我的需求了。所以TreeMap会根据插入k-v的key进行排序保存顺序。

map-2

讲讲Map对应的并发类

  1. Map对应的并发类有:java.util.concurrent.ConcurrentHashMap类和Collections.synchronizedMap(Map map)所修饰的类。

Map类图

map-summary

可以看到,4个map都实现了Map接口,HashTable作为远古类只实现了Map接口;而HashMap和TreeMap还继承了AbstractMap抽象类;其次,LinkedHashMap还继承自HashMap。


柒叶
409 声望43 粉丝