HashMap,TreeMap以及LinkedHashMap的区别

HashMap:HashMap数据是无序的,根据键的hashCode进行数据的存取,对数据的访问速度非常快,在map中插入删除

和定位元素,hashMap无疑是最好的选择,

TreeMap:里面的数据是有序的,底层是一个红黑树,如果想按照自定义顺序或者自然顺序存储数据,TreeMap是一个最好的选择

LinkedHashMap:他是hashMap的一个子类,底层维护了一个双向链表,他可以实现输入的顺序和输出的顺序相同

下面来讲讲LinkedHashMap是如何实现有序的:

LinkedHashMap具有可预知的迭代顺序,根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。

默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。  可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。

如何实现迭代有序?

  1. 重新定义了数组中保存的元素Entry(继承于HashMap.Entry),该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表。仍然保留next属性,所以既可像HashMap一样快速查找,用next获取该链表下一个Entry,也可以通过双向链接,通过after完成所有数据的有序迭代。
  2. accessOrder为true时,按访问顺序排序,false时,按插入顺序排序。默认false,即下文中recordAccess方法没有改变什么。 copy
  1. private final boolean accessOrder
  2. 存储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
    • HashMap.put:  
        
      public V put(K key, V value) {    
              if (key == null)    
                  return putForNullKey(value);    
              int hash = hash(key.hashCode());    
              int i = indexFor(hash, table.length);    
              for (Entry<K,V> e = table[i]; e != null; e = e.next) {    
                  Object k;    
                  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {    
                      V oldValue = e.value;    
                      e.value = value;    
                      e.recordAccess(this);    
                      return oldValue;    
                  }    
              }    
          
              modCount++;    
              addEntry(hash, key, value, i);    
              return null;    
          }
  1. 重写方法:
  2. void recordAccess(HashMap<K,V> m) {    
                LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;    
                if (lm.accessOrder) {    
                    lm.modCount++;    
                    remove();    
                    addBefore(lm.header);    
                }    
            }    
    void addEntry(int hash, K key, V value, int bucketIndex) {    
        // 调用create方法,将新元素以双向链表的的形式加入到映射中。    
        createEntry(hash, key, value, bucketIndex);    
        
        // 删除最近最少使用元素的策略定义    
        Entry<K,V> eldest = header.after;    
        if (removeEldestEntry(eldest)) {    
            removeEntryForKey(eldest.key);    
        } else {    
            if (size >= threshold)    
                resize(2 * table.length);    
        }    
    }    
    void createEntry(int hash, K key, V value, int bucketIndex) {    
        HashMap.Entry<K,V> old = table[bucketIndex];    
        Entry<K,V> e = new Entry<K,V>(hash, key, value, old);    
        table[bucketIndex] = e;    
        // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。    
        e.addBefore(header);    
        size++;    
    }    
    private void addBefore(Entry<K,V> existingEntry) {    
        after  = existingEntry;    
        before = existingEntry.before;    
        before.after = this;    
        after.before = this;    
    }

4.读取

同样调用recordAccess方法,是否将访问的当前节点移到链表尾部,与HashMap的区别是:当LinkedHashMap按访问顺序排序的时候,会将访问的当前节点移到链表尾部(头结点的前一个节点)。

public V get(Object key) {    
    // 调用父类HashMap的getEntry()方法,取得要查找的元素。    
    Entry<K,V> e = (Entry<K,V>)getEntry(key);    
    if (e == null)    
        return null;    
    // 记录访问顺序。    
    e.recordAccess(this);    
    return e.value;    
}

view plai

5.迭代view plain copy

//返回链表下个节点的引用  
Entry<K,V> nextEntry() {  
    //快速失败机制  
    if (modCount != expectedModCount)  
        throw new ConcurrentModificationException();  
    //链表为空情况  
    if (nextEntry == header)  
        throw new NoSuchElementException();  
      
    //给lastReturned赋值,最近一个从迭代器返回的节点对象  
    Entry<K,V> e = lastReturned = nextEntry;  
    nextEntry = e.after;  
    return e;  
}

下面来讲讲TreeMap是如何实现有序的:

TreeMap底层是一个红黑树,那么他的中序遍历就是有序的,因此treeMap是可以实现有序的,那么他又是如何实现自定义排序的呢?

1、让元素自身具备比较功能

		实现Comparable接口,重写comparaTo()方法。
		@Override
		public int compareTo(Object o) {

			Person p = (Person) o;
			int temp = this.age - p.age;
			return temp == 0?this.name.compareTo(p.name):temp;

	//		Person p = (Person) o;
	//		if(this.age > p.age)
	//			return 1;
	//		if(this.age < p.age)
	//			return -1;
	//		else {
	//			return this.name.compareTo(p.name);
	//		}
		}

2、如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。也就是对象不是自己定义的,怎么办?

可以使用TreeSet集合的第二种排序方式:

让集合自身具备比较功能,使用比较器,定义一个类实现Comparator接口,覆盖compare方法,将该类对象作为参数

传递给TreeSet集合的构造函数

原文地址:http://blog.51cto.com/12222886/2068550

时间: 2024-11-08 23:49:50

HashMap,TreeMap以及LinkedHashMap的区别的相关文章

HashMap与LinkedHashMap的区别

HashMap与LinkedHashMap的区别: 一般情况下,我们用的最多的是HashMap,在Map 中插入.删除和定位元素,HashMap 是最好的选择.但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好.如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列.工作流当中使用LinkedHashMap的好处是可以按照遍历集合的顺序来存值排列.

【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap

参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashcode()和equals() hashcode()和equals()即用于识别对象的身份. 在HashMap或类似的实现中,查找一个对象,是通过hashcode()返回的散列值映射到一个范围内的下标,在通过equals()比较此下标连接的链表是否存在相同的对象. 简单来说,hashcode()用于参考.快速定位

HashMap与HashTable联系与区别

HashMap与HashTable 1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法. 2.hashTable同步的,而HashMap是非同步的,效率上比hashTable要高,HashMap不是线程安全的 ,HashTable是线程安全的一个Collection.3.hashMap允许空键值,而hashTable不允许. ashtable继承自Dictionary类,而HashMap是Map接口的一个实

从头认识java-15.7 Map(7)-TreeMap与LinkedHashMap

这一章节我们来讨论一下Map两个比较常用的实现:TreeMap与LinkedHashMap. 1.TreeMap 特性:按照key来排序 package com.ray.ch14; import java.util.Comparator; import java.util.TreeMap; public class Test { public static void main(String[] args) { TreeMap<Integer, String> map = new TreeMap

HashMap、TreeMap、LinkedHashMap、hashtable的区别

Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复     hashMap是hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许有空键值,由于非线程安全,效率上面可能高于Hashtable. HashMap允许将null作为一个entry的key或者value,而hashtable不允许 hashMap把hashtable的contains方法去掉了,改成了containsvalue和containsKey

HashMap、TreeMap、LinkedHashMap、hashtable的区别 小记

Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复     hashMap是hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许有空键值,由于非线程安全,效率上面可能高于Hashtable.     HashMap允许将null作为一个entry的key或者value,而hashtable不允许     hashMap把hashtable的contains方法去掉了,改成了containsvalue和con

HashTable HashMap TreeMap LinkedHashMap 区别

参考:http://blog.csdn.net/xiaodifa995455120/article/details/7277441 http://www.apkbus.com/forum.php?mod=viewthread&tid=52426 Hashmap 是一个 最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度.HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个

HashMap 、LinkedHashMap、HashTable、TreeMap 和 Properties 的区别

HashMap 1.线程不安全: 2.允许null value 和 null key: 3.访问效率比较高: 4.Java1.2引进的Map接口的一个实现: 5.轻量级: 6.根据键的HashCode()值存储数据的位置: 7.遍历时,取得的数据的顺序是完全随机的: 8.最多允许一条记录的键为空: 9.允许多条记录的值为空: 10.在Map中插入.删除和定位元素,HashMap是较好的选择: LinkedHashMap 1.保存了记录的插入顺序: 2.可以按照插入顺序或应用次数排序: 3.如果需

10 HashMap,Map.Entry,LinkedHashMap,TreeMap,Hashtable,Collections类

Map集合的功能概述 添加功能 * V put(K key,V value):添加元素.            * 如果键是第一次存储,就直接存储元素,返回null            * 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值 删除功能 * void clear():移除所有的键值对元素        * V remove(Object key):根据键删除键值对元素,并把值返回 判断功能 * boolean containsKey(Object key):判断集合是否包