• LinkedHashMap


    1、开始
    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
    继承了类HashMap,实现了Map接口
    
    2、属性
    
        //双向链表,用于记录所有的元素
        private transient Entry<K,V> header;
    
        //遍历顺序【访问顺序或插入顺序】,默认插入顺序
        private final boolean accessOrder;
    
    
    3、双向链表
    
         private static class Entry<K,V> extends HashMap.Entry<K,V> {
             //双向链表中的上一个节点before和下一个节点after
            Entry<K,V> before, after;
    
            Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
                super(hash, key, value, next);
            }
    
            //从双向链表中删除元素
            private void remove() {
                //改变当前节点的前后两个节点的引用关系,若当前节点没有被引用,则才可以被GC回收
                //将前一个节点的after指向后一个节点
                before.after = after;
                //将后一个节点的before指向前一个节点
                after.before = before;
            }
    
            //将当前节点插入到指定节点的链表中,即指定节点的前面
            private void addBefore(Entry<K,V> existingEntry) {
                //指定当前节点与前后节点的引用关系
                //将当前节点的后一个节点指向指定节点
                after  = existingEntry;
                //将当前节点的前一个节点指向指定节点的前一个节点
                before = existingEntry.before;
    
                //指定前后节点与当前节点的引用关系
                //当前节点的前一个节点的后一个节点就是当前节点
                before.after = this;
                //当前节点的后一个节点的前一个节点就是当前节点
                after.before = this;
            }
    
               //查询或修改元素时调用
            void recordAccess(HashMap<K,V> m) {
                LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
                if (lm.accessOrder) {
                    //当时按访问顺序时,即最近较少使用顺序LRU
                    lm.modCount++;
                    //删除当前节点
                    remove();
                    //当当前节点添加到链表尾部
                    addBefore(lm.header);
                }
            }
    
            //删除元素时调用
            void recordRemoval(HashMap<K,V> m) {
                remove();
            }
        }
    
    4、构造器
    
        //指定容量和加载因子,遍历顺序为插入顺序
        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(m);
            accessOrder = false;
        }
        //指定容量和加载因子,以及遍历顺序
        public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
            super(initialCapacity, loadFactor);
            this.accessOrder = accessOrder;
        }
    
        //构造对象时,初始化双向链表
        @Override
        void init() {
            //初始化头节点
            header = new Entry<>(-1, null, null, null);
            //头结点即是其自身的前一个也是后一个
            header.before = header.after = header;
        }
    
    5、添加
    
        //添加时,重写了HashMap的此方法
         void addEntry(int hash, K key, V value, int bucketIndex) {
            super.addEntry(hash, key, value, bucketIndex);
    
            //头结点的第一个节点
            Entry<K,V> eldest = header.after;
            if (removeEldestEntry(eldest)) {
                //删除第一个节点
                removeEntryForKey(eldest.key);
            }
        }
    
        //新增节点
        void createEntry(int hash, K key, V value, int bucketIndex) {
            //获取老链表
            HashMap.Entry<K,V> old = table[bucketIndex];
            //新增节点
            Entry<K,V> e = new Entry<>(hash, key, value, old);
            //添加到数组中
            table[bucketIndex] = e;
            //当前节点添加到头结点尾部,添加使用前插法
            e.addBefore(header);
            //计数
            size++;
        }
    
        //是否删除第一个节点,即老的节点
        protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return false;
        }
    
    6、查找
    
        public V get(Object key) {
            Entry<K,V> e = (Entry<K,V>)getEntry(key);
            if (e == null)
                return null;
            //记录查找的元素,用于根据访问的顺序时,维护双向链表
            e.recordAccess(this);
            return e.value;
        }
    
    参考资料:
    http://www.cnblogs.com/tstd/p/5059589.html
  • 相关阅读:
    mysql 数据库字符集问题
    适配器模式
    thinkphp学习笔记
    StarDict
    dereferencing pointer to incomplete type
    转载的一篇 关于git的
    策略模式
    让你的Ubuntu看的更顺眼些
    vim 配置
    .NET WEB SERVICE 学习记录
  • 原文地址:https://www.cnblogs.com/xiaoxian1369/p/5634050.html
Copyright © 2020-2023  润新知