JAVA的Map类:HashMap,LinkedHashMap,TreeMap,ConcurrentHashMap,WeakReferenceHashMap

来源:互联网 发布:雅思在线模拟考试软件 编辑:程序博客网 时间:2024/06/08 15:33

首先是HashMap。HashMap实现算法是哈希表,实现的数据结构是链表与数组。初始化的参数有初始容量(initialCapacity)和装载因子(loadFactor)。哈希表通过某种算法,将对象进行分类,每一类即是一个桶,桶由数组实现,桶的数量也是数组的大小,就是初始容量。对于冲突,通过在每一个桶下挂一个链表来解决。装载因子表示哈希表的元素拥挤程度,其计算公式为:α= n/m。其中,n为元素数量,m为容量,也就是桶的个数。当装载因子达到预设的值时,哈希表便会进行再散列,扩充桶的数量。HashMap的遍历是按桶的顺序进行遍历,并依次遍历桶中的元素。Java中,HashMap在初始化时,初始容量与装载因子默认为16和0.75f。HashMap中每条记录(entry)有键(key)与值(value)两个属性。其中,键(key)作为记录(entry)的唯一标识,不可重复。HashMap在内部构建了两个Set,keySet与entrySet,可以通过foreach循环来进行访问, 也可使用iterator迭代器进行访问。KeySet会遍历两次,第一次先转为iterator,第二次再取出value,而entrySet只会遍历一次,所以一般选用entrySet进行遍历。


相比于HashTable,HashMap非线程安全,效率也比较高,还可以插入null的键值。HashTable是线程安全的,效率也就偏低,而且不能插入null键值。


还有一组类似的就是Vector与ArrayList,Vector是线程安全的,效率低;ArrayList是非线程安全的,效率要高。


LinkedHashMap是HashMap的子类,继承自HashMap,但它与HashMap不同的地方在于,它除了使用哈希表来保存元素,还构建了一个双向循环链表来记录元素的顺序。LinkedHashMap中,记录元素的顺序有两种选择,一是插入顺序,也是默认顺序,二是访问顺序,即每次被访问的元素都会被插入到双向链表的尾部。因此,在Java中,LinkedHashMap的初始化参数有三个,除了初始容量(initialCapacity)和装载因子(loadFactory),还有boolean型的访问顺序(accessOrder)。accessOrder设置为true,就会按访问顺序来对元素进行排序,否则,按插入顺序对元素进行排序。LRUCache实现便是借助LinkedHashMap可以按照访问顺序对元素进行排序的特点。


LinkedHashMap处于按插入顺序遍历的模式仅对新插入的entry有效。如果新插入的<key,value> 对应的key已经存在,对应的Entry在遍历顺序中的位置并不会改变。


TreeMap与HashMap并列,都继承自AbstractMap,它的实现算法是红黑树,在遍历时按照预先设定的排序算法有序的访问元素。同样的,TreeMap也可以借助keySet与entrySet来进行访问。TreeMap的键不可以为null。

关于红黑树,可以参看wiki百科 https://en.wikipedia.org/wiki/Red%E2%80%93black_tree

红黑树在操作时,无法保证每次操作完成之后都是一棵平衡的二叉树,但由于其操作简单,Java的在是实现TreeMap与TreeSet时,还是选择了它。


ConcurrentHashMap是java.util.concurrent包里面新加入的数据结构。它与HashMap的操作类似,但键与值不可以插入null,但却保证了线程安全,效率也没有变低。

相比于HashTable将每个方法都进行了synchronized同步,ConcurrentHashMap使用了分段锁,将整个Map分成了若干个Segment。

但是注意,ConcurrentHashMap只是保证了在同一时刻只有读/写的操作,即保证每次从里面读取的数据都是最新的。当你有多个线程对ConcurrentHashMap进行读写之外的其它操作时,还是要使用锁来保证同步性的。


WeakReferenceHashMap是弱引用HashMap。如果WeakReferenceHashMap里的对象仅有WeakReferenceHashMap引用的话,那么在下一次的垃圾回收时,它就会被gc线程回收掉。使用WeakReferenceHashMap主要是为了防止OOM。

1 0
原创粉丝点击