HashMap,TreeMap以及LinkedHashMap的区别
原文:https://blog.51cto.com/12222886/2068550
HashMap:HashMap数据是无序的,根据键的hashCode进行数据的存取,对数据的访问速度非常快,在map中插入删除
和定位元素,hashMap无疑是最好的选择,
TreeMap:里面的数据是有序的,底层是一个红黑树,如果想按照自定义顺序或者自然顺序存储数据,TreeMap是一个最好的选择
LinkedHashMap:他是hashMap的一个子类,底层维护了一个双向链表,他可以实现输入的顺序和输出的顺序相同
下面来讲讲LinkedHashMap是如何实现有序的:
LinkedHashMap具有可预知的迭代顺序,根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。
默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。 可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。
如何实现迭代有序?
-
重新定义了数组中保存的元素Entry(继承于HashMap.Entry),该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表。仍然保留next属性,所以既可像HashMap一样快速查找,用next获取该链表下一个Entry,也可以通过双向链接,通过after完成所有数据的有序迭代。
-
accessOrder为true时,按访问顺序排序,false时,按插入顺序排序。默认false,即下文中recordAccess方法没有改变什么。 copy
-
存储put
LinkedHashMap并未重写父类HashMap的put方法,而是重写了父类HashMap的put方法调用的子方法void recordAccess(HashMap m),void addEntry(int hash, K key, V value, int bucketIndex) 和void createEntry(int hash, K key, V value, int bucketIndex),提供了自己特有的双向链接列表的实现。
-
put时,key已存在,替换value(同HashMap),并调用recordAccess方法,方法作用为根据accessOrder的值保持链表顺序不变或者将将访问的当前节点移到链表尾部(头结点的前一个节点)。
-
key不存在,添加新的Entry,仍然是Table[i]= newEntry,旧链表首个为newEntry.next(同HashMap),将newEntry加到双向链表末尾(即header前,这样就保留了插入顺序)。copy
-
重写方法:
4.读取
同样调用recordAccess方法,是否将访问的当前节点移到链表尾部,与HashMap的区别是:当LinkedHashMap按访问顺序排序的时候,会将访问的当前节点移到链表尾部(头结点的前一个节点)。
5.迭代view plain copy
下面来讲讲TreeMap是如何实现有序的:
TreeMap底层是一个红黑树,那么他的中序遍历就是有序的,因此treeMap是可以实现有序的,那么他又是如何实现自定义排序的呢?
1、让元素自身具备比较功能
2、如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。也就是对象不是自己定义的,怎么办?
可以使用TreeSet集合的第二种排序方式:
让集合自身具备比较功能,使用比较器,定义一个类实现Comparator接口,覆盖compare方法,将该类对象作为参数
传递给TreeSet集合的构造函数

浙公网安备 33010602011771号