1. 程式人生 > >java集合類學習筆記之LinkedHashMap

java集合類學習筆記之LinkedHashMap

super 增長 remove sta extend red for normal 順序

1、簡述

    LinkedHashMap是HashMap的子類,他們最大的不同是,HashMap內部維護的是一個單向的鏈表數組,而LinkedHashMap內部維護的是一個雙向的鏈表數組。HashMap是無序的,LinkedHashMap可以根據訪問順序或者插入順序進行排序(默認是根據插入順序的,當設置accessOrder為true時會按照訪問順序排序),當按照訪問順序排序的時候,每次get或put操作時,都會將該節點放到鏈表的末尾

2、實現

  1、數據結構:

    LinkedHashMap是HashMap的子類,它的內部同樣是使用了hashMap定義的鏈表數組存儲的數據。只不過在HashMap中使用的是單想鏈表Node<k,v>作為每個節點,而LinkedHashMap使用了集成了HashMap.Node<k,v>的雙向鏈表Entry<k,v>來作為每個節點,Entry<k,v>在Node<k,v>的基礎上增加了Entry<K,V> before, after兩個屬性,將數組中的前後元素關聯起來,這樣的實現也為LinkedHashMap根據插入順序或訪問順序提供了可能

  2、構造方法:

    LinkedHashMap是HashMap的子類,它提供了五種構造方法,

 public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }
public LinkedHashMap() { super(); accessOrder = false; } public LinkedHashMap(Map<? extends K, ? extends V> m) { super(); accessOrder = false; putMapEntries(m, false); } public LinkedHashMap(int initialCapacity, float loadFactor,
boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }

    從以上我們可以看出,前面四中構造方法都是默認的accessOrder=false,即按找插入順序排序,第五種構造方法我們可以自己定義accessOrder的值,當為true時,說明是按照訪問順序排序的,每次put或get操作的時候都會將元素移到鏈表的末尾

  3、LinkedHashMap操作

      由於LinkedHashMap繼承了HashMap類,而且並沒有重寫put,get等方法,所以在這裏對於LinkedHashMap的基礎操作的源碼就不再分析,感興趣的可以參考上一篇關於HashMap的學習筆記。在這裏重點看一下LinkedHashMap提供的removeEldestEntry(Map.Entry<K,V> eldest)方法

    

/**
     * Returns <tt>true</tt> if this map should remove its eldest entry.
     * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
     * inserting a new entry into the map.  It provides the implementor
     * with the opportunity to remove the eldest entry each time a new one
     * is added.  This is useful if the map represents a cache: it allows
     * the map to reduce memory consumption by deleting stale entries.
     *
     * <p>Sample use: this override will allow the map to grow up to 100
     * entries and then delete the eldest entry each time a new entry is
     * added, maintaining a steady state of 100 entries.
     * <pre>
     *     private static final int MAX_ENTRIES = 100;
     *
     *     protected boolean removeEldestEntry(Map.Entry eldest) {
     *        return size() &gt; MAX_ENTRIES;
     *     }
     * </pre>
     *
     * <p>This method typically does not modify the map in any way,
     * instead allowing the map to modify itself as directed by its
     * return value.  It <i>is</i> permitted for this method to modify
     * the map directly, but if it does so, it <i>must</i> return
     * <tt>false</tt> (indicating that the map should not attempt any
     * further modification).  The effects of returning <tt>true</tt>
     * after modifying the map from within this method are unspecified.
     *
     * <p>This implementation merely returns <tt>false</tt> (so that this
     * map acts like a normal map - the eldest element is never removed).
     *
     * @param    eldest The least recently inserted entry in the map, or if
     *           this is an access-ordered map, the least recently accessed
     *           entry.  This is the entry that will be removed it this
     *           method returns <tt>true</tt>.  If the map was empty prior
     *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
     *           in this invocation, this will be the entry that was just
     *           inserted; in other words, if the map contains a single
     *           entry, the eldest entry is also the newest.
     * @return   <tt>true</tt> if the eldest entry should be removed
     *           from the map; <tt>false</tt> if it should be retained.
     */
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

    這個方法就是判斷是否需要刪除LinkedHashMap中最舊的元素,默認是false的。當我們需要利用hashmap做一些數據的緩存,可能有的數據是使用了一兩次之後就失去了價值,此外我們也不想看到緩存的map無限的增長又不想自己手動的去維護這個map。此時我們就可以使用LinkedHashMap來完成這個功能;

public class Demo {
    static class MyMap<k,v> extends LinkedHashMap<k,v>{    //定義一個繼承LinkedHashMap的類,並重寫removeEldestEntry方法
        int size;
        public MyMap (int size){        //只提供一個有參的構造方法,用來設置map的大小
            /*
             * 這裏調用的是LinkedHashMap的LinkedHashMap(int initialCapacity,boolean accessOrder)
             * 構造方法,設置按訪問順序排序
             */
            super(16,0.75f,true);        
            this.size = size;
        }
        @Override
        protected boolean removeEldestEntry(Entry<k, v> eldest) {
            // TODO Auto-generated method stub
            return this.size<size();    //設置當map裏面存放的元素超過MyMap設置的size時就刪除最老的元素
        }
        
    }
    public static void main(String[] args) {
        Map<String,String> map = new MyMap<String,String>(5);    
        for (int i = 0; i < 10; i++) {
            map.put(i+"", i+"");
            System.out.print(i+"="+map.size()+"\t");
        }
        System.out.println();
        //遍歷map看看裏面的元素
        map.forEach((k,v)->{
            System.out.println("k="+k);
        });
        
        //此時訪問一下裏面的元素,再觀察遍歷後的順序
        map.get("6");map.get("8");
        System.out.println("========================");
        map.forEach((k,v)->{
            System.out.println("k="+k);
        });
    }
}

打印的結果:
  

0=1 1=2 2=3 3=4 4=5 5=5 6=5 7=5 8=5 9=5
k=5
k=6
k=7
k=8
k=9
========================
k=5
k=7
k=9
k=6
k=8

 

  

總結:

    在學完LinkedHashMap和HashMap之後我們會發現,這兩種集合類是非常相似的,二者都是通過內部數組去保存數據的,不同的是HashMap數組中的每個元素都是一個單向的鏈表,指向了產生hash沖突時和它本身具有相同hash值的元素,所以HashMap只能是無序的。LinkedHashMap中數組裏面的每一個元素都是一個雙向鏈表,它不僅指向了產生hash沖突時下一個跟它本身具有相同hash值的位置,還指定了它的上一個和下一個元素(可以是插入順序的上一個下一個,也可以試訪問順序的上一個下一個),這樣為LinkedHashMap實現有序提供了可能

java集合類學習筆記之LinkedHashMap