Java中的Map

Map散列表

HashMap与LinkedHashMap

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

《Java中的Map》

《Java中的Map》

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

《Java中的Map》

网上关于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的数组的索引范围。

《Java中的Map》

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

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

HashTable

《Java中的Map》

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

TreeMap

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

《Java中的Map》

讲讲Map对应的并发类

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

Map类图

《Java中的Map》

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

    原文作者:算法小白
    原文地址: https://segmentfault.com/a/1190000016524871
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞