现在的位置: 首页 > 综合 > 正文

Java学习札记1:LinkedHashMap

2018年04月04日 ⁄ 综合 ⁄ 共 3261字 ⁄ 字号 评论关闭

 

LinkedHashMap是Map具有可预知的迭代顺序的实现,支持所有的可选操作。

Key和Value可以是任意值,包括null。

所有的条目都保存在双链表中。默认的迭代顺序是将键插入到Map中的顺序。重复插入一个已存在的键值不会改变插入顺序。如果使用了三个参数的构造函数,并且accessOrder指定为true,则迭代顺序为条目被访问的顺序。访问顺序受到put,get,和putAll操作的影响,但不受collection 视图操作的影响。

注意:LinkedHashMap的实现不是同步的。如果多个线程同时访问Map,而其中至少一个线程从结构上修改了Map,则LinkedHashMap必须保持同步。对于迭代顺序为插入顺序的Map实例,结构修改是指移除或添加一个条目的操作。对于迭代顺序为访问顺序的Map实例,结构修改是指put,get和putAll这些方法对条目顺序的改变。对于条目中Value的改变不算是结构修改。

假如Map正在改变结构,与此同时,迭代器正好迭代过这些元素,那么,迭代器就有可能抛出ConcurrentModificationException。只有迭代器提供的remove方法允许在迭代过程中移除元素。但不能保证这种机制能够在异步并发修改中起作用。这只能使用在调试情况下。

LinkedHashMap继承自HashMap,内部自己维护了一个运行于所有条目的双向链表。

1、类结构

public class LinkedHashMap<K, V> extends HashMap<K, V> implements Map<K, V>


2、重要的成员变量

 

/**                                                                     
 * The head of the doubly linked list.                                  
 */                                                                     
private transient Entry<K, V> header;                                   
                                                                        
/**                                                                     
 * The iteration ordering method for this linked hash map: <tt>true</tt>
 * for access-order, <tt>false</tt> for insertion-order.                
 *                                                                      
 * @serial                                                              
 */                                                                     
private final boolean accessOrder;                                      

 

其中Entry类是LinkedHashMap的内部定义,代码片段如下:

//继承了HashMap.Entry                                       
private static class Entry<K, V> extends HashMap.Entry<K, V>
//新增的两个成员变量                                        
Entry<K, V> before, after;                                  

 

3、重要的方法

   /**
     * This override alters behavior of superclass put method. It causes newly
     * allocated entry to get inserted at the end of the linked list and
     * removes the eldest entry if appropriate.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        createEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed, else grow capacity if appropriate
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        } else {
            if (size >= threshold) 
                resize(2 * table.length);
        }
    }

    /**
     * This override differs from addEntry in that it doesn't resize the
     * table or remove the eldest entry.
     */
    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;
        e.addBefore(header);
        size++;
    }

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

 

当有新条目加入Map的时候,会调用addEntry方法,addEntry方法又会调用removeEldestEntry方法,这里就是实现LRU算法元素过期机制的地方,默认的情况下,removeEldestEntry方法只返回false,即表示该元素永远不会过期。

4、基本LinkedHashMap的实现

public static class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {

        /** serialVersionUID */
        private static final long serialVersionUID = -5933045562735378538L;

        /** 最大数据存储容量 */
        private static final int  LRU_MAX_CAPACITY     = 1024;

        /** 存储数据容量  */
        private int               capacity;

        /**
         * 默认构造方法
         */
        public LRULinkedHashMap() {
            super();
        }

        /**
         * 带参数构造方法
         * @param initialCapacity   容量
         * @param loadFactor        装载因子
         * @param isLRU             是否使用LRU算法,true:使用(按方案顺序排序);false:不使用(按存储顺序排序)
         */
        public LRULinkedHashMap(int initialCapacity, float loadFactor, boolean isLRU) {
            super(initialCapacity, loadFactor, true);
            capacity = LRU_MAX_CAPACITY;
        }

        /**
         * 带参数构造方法
         * @param initialCapacity   容量
         * @param loadFactor        装载因子
         * @param isLRU             是否使用LRU算法,true:使用(按方案顺序排序);false:不使用(按存储顺序排序)
         * @param lruCapacity       lru存储数据容量       
         */
        public LRULinkedHashMap(int initialCapacity, float loadFactor, boolean isLRU, int lruCapacity) {
            super(initialCapacity, loadFactor, true);
            this.capacity = lruCapacity;
        }

        /** 
         * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
         */
        @Override
        protected boolean removeEldestEntry(Entry<K, V> eldest) {
            System.out.println(eldest.getKey() + "=" + eldest.getValue());
            
            if(size() > capacity) {
                return true;
            }
            return false;
        }
    }
参考资料:
1、基于LinkedHashMap实现LRU缓存调度算法原理及应用http://woming66.iteye.com/blog/1284326
2、自己动手写写:LinkedHashMap源码浅析http://boy00fly.iteye.com/blog/1144691

抱歉!评论已关闭.