从HashMap到LruCache的源码分析

来源:互联网 发布:mac视频播放器推荐 编辑:程序博客网 时间:2024/05/23 00:09
android的图片加载库Android-Universal-Image-Loader中的缓存策略,内存缓存LruCache,是一个最近最少使用算法LRU。前几天看操作系统也看到了LRU算法,是用在缺页中断发生时,进行置换算法才用的一种。缓存中的LruCache和操作系统中的页置换算法思想是一样的,于是心血来潮,决定把这部分实现看看,然后就有了这篇博客,从HashMap的实现到LinkedHashMap再到LruCache,总共包含三个类的源码分析,花费了整整一晚上。

HashMap的实现中主要维护一个数组,发生冲突通过链表来解决,链表插入类似于头插法
LinkedHashMap继承自HashMap,在hash的基础上,又维护了一个链表,这个链表是带头结点的双向循环链表,需要注意的链表的元素都是hash里面的元素,链表仅仅是在hash的基础上用指针将hash中的节点连接了起来

LruCache是android的utils包里面的一个类,用来实现缓存防止OOM的一个工具类,用途非常广泛。

关于LRU算法:Least Recently Used最近最少使用算法,在操作系统中,对内存的访问满足局部性原理,于是LRU用在缺页中断发生时的置换算法,将内存中的最近最长未使用的页面置换到磁盘,可以实现的方式可以为维护一个链表,当访问一个页面是,将该页面移动至表头(尾),发生缺页时取链表最后(前)的页面置换,这样存在问题是读取某个页面的复杂度太高,于是可以考虑将其进行hash,这样读取速度会提高,于是用到了LinkedHashMap这种数据结构。

android实现的LruCache类主要使用来进行内存缓存的,维护所用资源的强引用,当内存超过设定的缓存值时,将好久未使用的资源从内存删除。

LruCache的实现中在缓存的值达到最大值时采用的方法是,循环迭代从链表中取eldest的元素进行删除,知道占用的控件小于最大的缓存值。LinkedHashMap中提供的removeEldestEntry函数可以简单实现LRU的功能,但不能很好的满足一些场景,因为里面存放的元素的大小不总是大小一致的,或者说不仅仅是以缓存数据的个数来看的。

下面基本上没有太多的文字,所有的解释都详细的列在代码里面

HashMap

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/HashMap.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable{  
  2.     // 默认初始容量16  
  3.     static final int DEFAULT_INITIAL_CAPACITY = 16;  
  4.     // 最大容量2^30  
  5.     static final int MAXIMUM_CAPACITY = 1 << 30;  
  6.     // 默认加载因子  
  7.     static final float DEFAULT_LOAD_FACTOR = 0.75f;  
  8.     // hash映射的数组槽  
  9.     transient Entry[] table;  
  10.     // 元素个数  
  11.     transient int size;  
  12.     // 阈值 = 加载因子 * 容量  
  13.     int threshold;  
  14.   
  15.     // 加载因子  
  16.     final float loadFactor;  
  17.   
  18.     // 修改次数,判断迭代期间容器被修改,不然抛出ConcurrentModificationException  
  19.     transient int modCount;  
  20.   
  21.     public HashMap(int initialCapacity, float loadFactor) {  
  22.         if (initialCapacity < 0)  
  23.             throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);  
  24.         // 参数调整  
  25.         if (initialCapacity > MAXIMUM_CAPACITY)  
  26.             initialCapacity = MAXIMUM_CAPACITY;  
  27.         if (loadFactor <= 0 || Float.isNaN(loadFactor))  
  28.             throw new IllegalArgumentException("Illegal load factor: " + loadFactor);  
  29.   
  30.         // 找到大于initialCapacity的最小的2次幂  
  31.         int capacity = 1;  
  32.         while (capacity < initialCapacity)  
  33.             capacity <<= 1;  
  34.   
  35.         this.loadFactor = loadFactor;  
  36.         // 设置阈值  
  37.         threshold = (int)(capacity * loadFactor);  
  38.         // 定义数组,大小为capacity  
  39.         table = new Entry[capacity];  
  40.         // 这里是空的实现,实际让其子类覆写该方法  
  41.         init();  
  42.     }  
  43.   
  44.     public HashMap(int initialCapacity) {  
  45.         this(initialCapacity, DEFAULT_LOAD_FACTOR);  
  46.     }  
  47.   
  48.     // 默认情况下默认的加载因子,默认的容量16  
  49.     public HashMap() {  
  50.         this.loadFactor = DEFAULT_LOAD_FACTOR;  
  51.         threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  
  52.         table = new Entry[DEFAULT_INITIAL_CAPACITY];  
  53.         init();  
  54.     }  
  55.   
  56.     // 从已存在的Map创建HashMap  
  57.     public HashMap(Map<? extends K, ? extends V> m) {  
  58.         // 容量为Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY),默认的加载因子  
  59.         this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,  DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);  
  60.         // 遍历m将其元素添加到hashmap中  
  61.         putAllForCreate(m);  
  62.     }  
  63.   
  64.     void init() {  
  65.     }  
  66.   
  67.     // hash算法  
  68.     // 可以将1变的松散,可以减少冲突  
  69.     static int hash(int h) {  
  70.         // This function ensures that hashCodes that differ only by  
  71.         // constant multiples at each bit position have a bounded  
  72.         // number of collisions (approximately 8 at default load factor).  
  73.         h ^= (h >>> 20) ^ (h >>> 12);  
  74.         return h ^ (h >>> 7) ^ (h >>> 4);  
  75.     }  
  76.   
  77.     // 根据hash值获得在我们维护的数组的索引  
  78.     // 即取hash值的小于length的部分,这样才能将其限定在数组大小的范围里面,这样的处理也会带来冲突  
  79.     static int indexFor(int h, int length) {  
  80.         return h & (length-1);  
  81.     }  
  82.   
  83.     public int size() {  
  84.         return size;  
  85.     }  
  86.   
  87.     public boolean isEmpty() {  
  88.         return size == 0;  
  89.     }  
  90.   
  91.     // 根据键获取值  
  92.     public V get(Object key) {  
  93.         if (key == null)  
  94.             return getForNullKey();  
  95.         int hash = hash(key.hashCode());  
  96.         for (Entry<K,V> e = table[indexFor(hash, table.length)];  
  97.              e != null;  
  98.              e = e.next) {  
  99.             Object k;  
  100.             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
  101.                 return e.value;  
  102.         }  
  103.         return null;  
  104.     }  
  105.   
  106.     // 键为null的Entry都放在第0个槽中,相当于null经过hash后为0  
  107.     private V getForNullKey() {  
  108.         for (Entry<K,V> e = table[0]; e != null; e = e.next) {  
  109.             if (e.key == null)  
  110.                 return e.value;  
  111.         }  
  112.         return null;  
  113.     }  
  114.   
  115.     public boolean containsKey(Object key) {  
  116.         return getEntry(key) != null;  
  117.     }  
  118.   
  119.     // 返回对应键的Entry,若不存在返回null  
  120.     final Entry<K,V> getEntry(Object key) {  
  121.         // 计算key的hash值  
  122.         int hash = (key == null) ? 0 : hash(key.hashCode());  
  123.         // 根据hash值获取其存放的槽,即indexFor函数的作用  
  124.         // 遍历这个槽上的链表  
  125.         for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {  
  126.             Object k;  
  127.             // hash值一样且键一样(同一个内存地址或者值相同)即返回。  
  128.             if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))  
  129.                 return e;  
  130.         }  
  131.         return null;  
  132.     }  
  133.   
  134.   
  135.     // 添加键值对  
  136.     public V put(K key, V value) {  
  137.         // 如果键为null,那么存放在第0个槽上  
  138.         if (key == null)  
  139.             return putForNullKey(value);  
  140.         // 获得键的hash值  
  141.         int hash = hash(key.hashCode());  
  142.         // 根据hash值得到保存在我们维护的数组中的那个下标处  
  143.         int i = indexFor(hash, table.length);  
  144.         for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  145.             Object k;  
  146.             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
  147.                 // 已存在,修改  
  148.                 V oldValue = e.value;  
  149.                 e.value = value;  
  150.                 e.recordAccess(this);  
  151.                 // 将旧的值返回  
  152.                 return oldValue;  
  153.             }  
  154.         }  
  155.   
  156.         modCount++;  
  157.         // 不存在则添加  
  158.         addEntry(hash, key, value, i);  
  159.         return null;  
  160.     }  
  161.   
  162.     // 添加键位null的键值对  
  163.     private V putForNullKey(V value) {  
  164.         // 键位null的放在第0个槽  
  165.         for (Entry<K,V> e = table[0]; e != null; e = e.next) {  
  166.             if (e.key == null) {  
  167.                 // 已存在则替换  
  168.                 V oldValue = e.value;  
  169.                 e.value = value;  
  170.                 // 被子类覆盖  
  171.                 e.recordAccess(this);  
  172.                 return oldValue;  
  173.             }  
  174.         }  
  175.         modCount++;  
  176.         // 不存在,添加  
  177.         addEntry(0null, value, 0);  
  178.         return null;  
  179.     }  
  180.   
  181.     // 和put类似,用在构造函数、clone  
  182.     private void putForCreate(K key, V value) {  
  183.         int hash = (key == null) ? 0 : hash(key.hashCode());  
  184.         int i = indexFor(hash, table.length);  
  185.   
  186.         for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  187.             Object k;  
  188.             if (e.hash == hash &&  
  189.                 ((k = e.key) == key || (key != null && key.equals(k)))) {  
  190.                 e.value = value;  
  191.                 return;  
  192.             }  
  193.         }  
  194.         createEntry(hash, key, value, i);  
  195.     }  
  196.   
  197.     // 遍历map添加到新建的hashmap中  
  198.     private void putAllForCreate(Map<? extends K, ? extends V> m) {  
  199.         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())  
  200.             putForCreate(e.getKey(), e.getValue());  
  201.     }  
  202.   
  203.     // 扩容  
  204.     void resize(int newCapacity) {  
  205.         Entry[] oldTable = table;  
  206.         int oldCapacity = oldTable.length;  
  207.         // 旧的容量已经达到最大了,调整阈值即可  
  208.         if (oldCapacity == MAXIMUM_CAPACITY) {  
  209.             threshold = Integer.MAX_VALUE;  
  210.             return;  
  211.         }  
  212.         // 用新的容量创建新数组  
  213.         Entry[] newTable = new Entry[newCapacity];  
  214.         // 并将原数组里面的hash表全部搬移到新的数组槽中  
  215.         transfer(newTable);  
  216.         // 将维护的数组引用重新赋值  
  217.         table = newTable;  
  218.         // 调整阈值  
  219.         threshold = (int)(newCapacity * loadFactor);  
  220.     }  
  221.   
  222.     // 将原数组table里面的hash表全部搬移到新的数组槽中填充newTable  
  223.     void transfer(Entry[] newTable) {  
  224.         Entry[] src = table;  
  225.         int newCapacity = newTable.length;  
  226.         // 遍历数组的每个槽,每个槽中在一次遍历链表  
  227.         for (int j = 0; j < src.length; j++) {  
  228.             Entry<K,V> e = src[j];  
  229.             if (e != null) {  
  230.                 src[j] = null;  
  231.                 do {  
  232.                     Entry<K,V> next = e.next;  
  233.                     int i = indexFor(e.hash, newCapacity);  
  234.                     e.next = newTable[i];  
  235.                     newTable[i] = e;  
  236.                     e = next;  
  237.                 } while (e != null);  
  238.             }  
  239.         }  
  240.     }  
  241.   
  242.     //   
  243.     public void putAll(Map<? extends K, ? extends V> m) {  
  244.         // map元素个数为0,什么也不用做  
  245.         int numKeysToBeAdded = m.size();  
  246.         if (numKeysToBeAdded == 0)  
  247.             return;  
  248.         // 如果待复制的元素个数大于阈值,需要扩容  
  249.         if (numKeysToBeAdded > threshold) {  
  250.             // 目标容量为满足当前设置的加载因子情况下的容量  
  251.             int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);  
  252.             // 参数调整  
  253.             if (targetCapacity > MAXIMUM_CAPACITY)  
  254.                 targetCapacity = MAXIMUM_CAPACITY;  
  255.             int newCapacity = table.length;  
  256.             // 找到大于targetCapacity的最小2的n次幂  
  257.             while (newCapacity < targetCapacity)  
  258.                 newCapacity <<= 1;  
  259.             if (newCapacity > table.length)  
  260.                 // 扩容为新的容量  
  261.                 resize(newCapacity);  
  262.         }  
  263.   
  264.         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())  
  265.             put(e.getKey(), e.getValue());  
  266.     }  
  267.   
  268.     public V remove(Object key) {  
  269.         Entry<K,V> e = removeEntryForKey(key);  
  270.         return (e == null ? null : e.value);  
  271.     }  
  272.   
  273.     // 移除key所对应的键值对  
  274.     // 和removeMapping类似,只是在判断相等时有点区别  
  275.     final Entry<K,V> removeEntryForKey(Object key) {  
  276.         int hash = (key == null) ? 0 : hash(key.hashCode());  
  277.         int i = indexFor(hash, table.length);  
  278.         Entry<K,V> prev = table[i];  
  279.         Entry<K,V> e = prev;  
  280.   
  281.         while (e != null) {  
  282.             Entry<K,V> next = e.next;  
  283.             Object k;  
  284.             if (e.hash == hash &&  
  285.                 ((k = e.key) == key || (key != null && key.equals(k)))) {  
  286.                 modCount++;  
  287.                 size--;  
  288.                 if (prev == e)  
  289.                     table[i] = next;  
  290.                 else  
  291.                     prev.next = next;  
  292.                 // 依然在删除该键值对时调用,留给LinkedHashMap,因为可能会在访问hashmap时重新整理链表的指向关系  
  293.                 e.recordRemoval(this);  
  294.                 return e;  
  295.             }  
  296.             prev = e;  
  297.             e = next;  
  298.         }  
  299.         return e;  
  300.     }  
  301.   
  302.     // 移除键值对  
  303.     final Entry<K,V> removeMapping(Object o) {  
  304.         // 传递参数不是Entry的子类,什么也不做  
  305.         if (!(o instanceof Map.Entry))  
  306.             return null;  
  307.   
  308.         Map.Entry<K,V> entry = (Map.Entry<K,V>) o;  
  309.         Object key = entry.getKey();  
  310.         // 获取要删除的键值对的键的哈希值  
  311.         int hash = (key == null) ? 0 : hash(key.hashCode());  
  312.         // 根据hash值得到保存在我们维护的数组中的那个下标处  
  313.         int i = indexFor(hash, table.length);  
  314.         Entry<K,V> prev = table[i];  
  315.         Entry<K,V> e = prev;  
  316.   
  317.         while (e != null) {  
  318.             Entry<K,V> next = e.next;  
  319.             if (e.hash == hash && e.equals(entry)) {  
  320.                 // hash值相同并且entry内容一样,即找到了  
  321.                 modCount++;  
  322.                 size--;  
  323.                 if (prev == e)  
  324.                     table[i] = next;  
  325.                 else  
  326.                     prev.next = next;  
  327.                 // 空的实现,给LinkedHashMap实现,在删除键值对后执行  
  328.                 e.recordRemoval(this);  
  329.                 return e;  
  330.             }  
  331.             prev = e;  
  332.             e = next;  
  333.         }  
  334.         return e;  
  335.     }  
  336.   
  337.     public void clear() {  
  338.         modCount++;  
  339.         Entry[] tab = table;  
  340.         for (int i = 0; i < tab.length; i++)  
  341.             tab[i] = null;  
  342.         size = 0;  
  343.     }  
  344.   
  345.     // 判断是否包含值为value的键值对  
  346.     public boolean containsValue(Object value) {  
  347.         if (value == null)  
  348.             return containsNullValue();  
  349.   
  350.         Entry[] tab = table;  
  351.         for (int i = 0; i < tab.length ; i++)  
  352.             for (Entry e = tab[i] ; e != null ; e = e.next)  
  353.                 if (value.equals(e.value))  
  354.                     return true;  
  355.         return false;  
  356.     }  
  357.   
  358.     // 判断是否有值为null的键值对  
  359.     private boolean containsNullValue() {  
  360.         Entry[] tab = table;  
  361.         // 依次迭代数组和每个数组槽所对应的链表  
  362.         for (int i = 0; i < tab.length ; i++)  
  363.             for (Entry e = tab[i] ; e != null ; e = e.next)  
  364.                 if (e.value == null)  
  365.                     return true;  
  366.         return false;  
  367.     }  
  368.   
  369.     public Object clone() {  
  370.         HashMap<K,V> result = null;  
  371.         try {  
  372.             result = (HashMap<K,V>)super.clone();  
  373.         } catch (CloneNotSupportedException e) {  
  374.             // assert false;  
  375.         }  
  376.         result.table = new Entry[table.length];  
  377.         result.entrySet = null;  
  378.         result.modCount = 0;  
  379.         result.size = 0;  
  380.         result.init();  
  381.         result.putAllForCreate(this);  
  382.         return result;  
  383.     }  
  384.   
  385.     // hashmap的底层节点结构  
  386.     static class Entry<K,V> implements Map.Entry<K,V> {  
  387.         final K key;  
  388.         V value;  
  389.         Entry<K,V> next;  
  390.         final int hash;  
  391.   
  392.         Entry(int h, K k, V v, Entry<K,V> n) {  
  393.             value = v;  
  394.             next = n;  
  395.             key = k;  
  396.             hash = h;  
  397.         }  
  398.   
  399.         public final K getKey() {  
  400.             return key;  
  401.         }  
  402.   
  403.         public final V getValue() {  
  404.             return value;  
  405.         }  
  406.   
  407.         public final V setValue(V newValue) {  
  408.             V oldValue = value;  
  409.             value = newValue;  
  410.             return oldValue;  
  411.         }  
  412.   
  413.         public final boolean equals(Object o) {  
  414.             if (!(o instanceof Map.Entry))  
  415.                 return false;  
  416.             Map.Entry e = (Map.Entry)o;  
  417.             Object k1 = getKey();  
  418.             Object k2 = e.getKey();  
  419.             if (k1 == k2 || (k1 != null && k1.equals(k2))) {  
  420.                 Object v1 = getValue();  
  421.                 Object v2 = e.getValue();  
  422.                 if (v1 == v2 || (v1 != null && v1.equals(v2)))  
  423.                     return true;  
  424.             }  
  425.             return false;  
  426.         }  
  427.   
  428.         public final int hashCode() {  
  429.             return (key==null   ? 0 : key.hashCode()) ^  
  430.                    (value==null ? 0 : value.hashCode());  
  431.         }  
  432.   
  433.         public final String toString() {  
  434.             return getKey() + "=" + getValue();  
  435.         }  
  436.   
  437.         /*******两个空的方法,分别在添加和删除时调用,用以子类实现访问该容器时做一些其他操作*******/  
  438.         void recordAccess(HashMap<K,V> m) {  
  439.         }  
  440.         void recordRemoval(HashMap<K,V> m) {  
  441.         }  
  442.     }  
  443.   
  444.     // 添加一个Entry到bucketIndex槽的位置  
  445.     void addEntry(int hash, K key, V value, int bucketIndex) {  
  446.         Entry<K,V> e = table[bucketIndex];  
  447.         // 下面这句简单的表述实际上创建了一个Entry节点,下一个节点是e  
  448.         // 也就是说数组索引所在位置,然后在调整数组索引处为新创建的节点,即链表的头插法  
  449.         table[bucketIndex] = new Entry<>(hash, key, value, e);  
  450.         // 元素个数超过了阈值,进行扩容为原来的两倍  
  451.         if (size++ >= threshold)  
  452.             resize(2 * table.length);  
  453.     }  
  454.   
  455.     // 逻辑和addEntry一模一样,只是少了扩容的判断,该函数用在构造函数里拷贝另一个map的值  
  456.     // 此前已经调整了容量,因此不会出现扩容的情况  
  457.     void createEntry(int hash, K key, V value, int bucketIndex) {  
  458.         Entry<K,V> e = table[bucketIndex];  
  459.         table[bucketIndex] = new Entry<>(hash, key, value, e);  
  460.         size++;  
  461.     }  
  462.   
  463.     // 迭代器部分  
  464.     private abstract class HashIterator<E> implements Iterator<E> {  
  465.         Entry<K,V> next;        // next entry to return  
  466.         // 迭代器的fast-fail机制,迭代期间不允许修改容器  
  467.         int expectedModCount;   // For fast-fail  
  468.         int index;              // current slot  
  469.         Entry<K,V> current;     // current entry  
  470.   
  471.         HashIterator() {  
  472.             expectedModCount = modCount;  
  473.             if (size > 0) { // advance to first entry  
  474.                 Entry[] t = table;  
  475.                 while (index < t.length && (next = t[index++]) == null)  
  476.                     ;  
  477.             }  
  478.         }  
  479.   
  480.         public final boolean hasNext() {  
  481.             return next != null;  
  482.         }  
  483.   
  484.         final Entry<K,V> nextEntry() {  
  485.             if (modCount != expectedModCount)  
  486.                 throw new ConcurrentModificationException();  
  487.             Entry<K,V> e = next;  
  488.             if (e == null)  
  489.                 throw new NoSuchElementException();  
  490.   
  491.             if ((next = e.next) == null) {  
  492.                 Entry[] t = table;  
  493.                 while (index < t.length && (next = t[index++]) == null)  
  494.                     ;  
  495.             }  
  496.             current = e;  
  497.             return e;  
  498.         }  
  499.   
  500.         public void remove() {  
  501.             if (current == null)  
  502.                 throw new IllegalStateException();  
  503.             if (modCount != expectedModCount)  
  504.                 throw new ConcurrentModificationException();  
  505.             Object k = current.key;  
  506.             current = null;  
  507.             HashMap.this.removeEntryForKey(k);  
  508.             expectedModCount = modCount;  
  509.         }  
  510.     }  
  511.   
  512.     private final class ValueIterator extends HashIterator<V> {  
  513.         public V next() {  
  514.             return nextEntry().value;  
  515.         }  
  516.     }  
  517.   
  518.     private final class KeyIterator extends HashIterator<K> {  
  519.         public K next() {  
  520.             return nextEntry().getKey();  
  521.         }  
  522.     }  
  523.   
  524.     private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {  
  525.         public Map.Entry<K,V> next() {  
  526.             return nextEntry();  
  527.         }  
  528.     }  
  529.   
  530.     // Subclass overrides these to alter behavior of views' iterator() method  
  531.     Iterator<K> newKeyIterator()   {  
  532.         return new KeyIterator();  
  533.     }  
  534.     Iterator<V> newValueIterator()   {  
  535.         return new ValueIterator();  
  536.     }  
  537.     Iterator<Map.Entry<K,V>> newEntryIterator()   {  
  538.         return new EntryIterator();  
  539.     }  
  540.   
  541.     // Views  
  542.     // hasp里面的entry所对应的Set  
  543.     private transient Set<Map.Entry<K,V>> entrySet = null;  
  544.   
  545.     // 键对应的Set  
  546.     public Set<K> keySet() {  
  547.         Set<K> ks = keySet;  
  548.         return (ks != null ? ks : (keySet = new KeySet()));  
  549.     }  
  550.   
  551.     private final class KeySet extends AbstractSet<K> {  
  552.         public Iterator<K> iterator() {  
  553.             return newKeyIterator();  
  554.         }  
  555.         public int size() {  
  556.             return size;  
  557.         }  
  558.         public boolean contains(Object o) {  
  559.             return containsKey(o);  
  560.         }  
  561.         public boolean remove(Object o) {  
  562.             return HashMap.this.removeEntryForKey(o) != null;  
  563.         }  
  564.         public void clear() {  
  565.             HashMap.this.clear();  
  566.         }  
  567.     }  
  568.   
  569.   
  570.     public Collection<V> values() {  
  571.         Collection<V> vs = values;  
  572.         return (vs != null ? vs : (values = new Values()));  
  573.     }  
  574.   
  575.     // 值的集合  
  576.     private final class Values extends AbstractCollection<V> {  
  577.         public Iterator<V> iterator() {  
  578.             return newValueIterator();  
  579.         }  
  580.         public int size() {  
  581.             return size;  
  582.         }  
  583.         public boolean contains(Object o) {  
  584.             return containsValue(o);  
  585.         }  
  586.         public void clear() {  
  587.             HashMap.this.clear();  
  588.         }  
  589.     }  
  590.   
  591.     public Set<Map.Entry<K,V>> entrySet() {  
  592.         return entrySet0();  
  593.     }  
  594.   
  595.     private Set<Map.Entry<K,V>> entrySet0() {  
  596.         Set<Map.Entry<K,V>> es = entrySet;  
  597.         return es != null ? es : (entrySet = new EntrySet());  
  598.     }  
  599.   
  600.     private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {  
  601.         public Iterator<Map.Entry<K,V>> iterator() {  
  602.             return newEntryIterator();  
  603.         }  
  604.         public boolean contains(Object o) {  
  605.             if (!(o instanceof Map.Entry))  
  606.                 return false;  
  607.             Map.Entry<K,V> e = (Map.Entry<K,V>) o;  
  608.             Entry<K,V> candidate = getEntry(e.getKey());  
  609.             return candidate != null && candidate.equals(e);  
  610.         }  
  611.         public boolean remove(Object o) {  
  612.             return removeMapping(o) != null;  
  613.         }  
  614.         public int size() {  
  615.             return size;  
  616.         }  
  617.         public void clear() {  
  618.             HashMap.this.clear();  
  619.         }  
  620.     }  
  621.   
  622.     // 序列化部分  
  623.     private void writeObject(java.io.ObjectOutputStream s)  
  624.         throws IOException  
  625.     {  
  626.         Iterator<Map.Entry<K,V>> i =  
  627.             (size > 0) ? entrySet0().iterator() : null;  
  628.   
  629.         // Write out the threshold, loadfactor, and any hidden stuff  
  630.         s.defaultWriteObject();  
  631.   
  632.         // Write out number of buckets  
  633.         s.writeInt(table.length);  
  634.   
  635.         // Write out size (number of Mappings)  
  636.         s.writeInt(size);  
  637.   
  638.         // Write out keys and values (alternating)  
  639.         if (i != null) {  
  640.             while (i.hasNext()) {  
  641.                 Map.Entry<K,V> e = i.next();  
  642.                 s.writeObject(e.getKey());  
  643.                 s.writeObject(e.getValue());  
  644.             }  
  645.         }  
  646.     }  
  647.   
  648.     private static final long serialVersionUID = 362498820763181265L;  
  649.   
  650.     /** 
  651.      * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e., 
  652.      * deserialize it). 
  653.      */  
  654.     private void readObject(java.io.ObjectInputStream s)  
  655.          throws IOException, ClassNotFoundException  
  656.     {  
  657.         // Read in the threshold, loadfactor, and any hidden stuff  
  658.         s.defaultReadObject();  
  659.   
  660.         // Read in number of buckets and allocate the bucket array;  
  661.         int numBuckets = s.readInt();  
  662.         table = new Entry[numBuckets];  
  663.   
  664.         init();  // Give subclass a chance to do its thing.  
  665.   
  666.         // Read in size (number of Mappings)  
  667.         int size = s.readInt();  
  668.   
  669.         // Read the keys and values, and put the mappings in the HashMap  
  670.         for (int i=0; i<size; i++) {  
  671.             K key = (K) s.readObject();  
  672.             V value = (V) s.readObject();  
  673.             putForCreate(key, value);  
  674.         }  
  675.     }  
  676.   
  677.     // These methods are used when serializing HashSets  
  678.     int   capacity()     { return table.length; }  
  679.     float loadFactor()   { return loadFactor;   }  
  680. }  

LinkedHashMap

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/LinkedHashMap.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{  
  2.     private static final long serialVersionUID = 3801124242820219131L;  
  3.     // 带头结点的双向循环链表 的头  
  4.     private transient Entry<K,V> header;  
  5.     // 取值代表使用的方式:false链表按照添加顺序组织,true按照使用顺序组织  
  6.     private final boolean accessOrder;  
  7.   
  8.     // 在构造方法中accessOrder均被初始化为false  
  9.     public LinkedHashMap(int initialCapacity, float loadFactor) {  
  10.         super(initialCapacity, loadFactor);  
  11.         accessOrder = false;  
  12.     }  
  13.     public LinkedHashMap(int initialCapacity) {  
  14.         super(initialCapacity);  
  15.         accessOrder = false;  
  16.     }  
  17.     public LinkedHashMap() {  
  18.         super();  
  19.         accessOrder = false;  
  20.     }  
  21.     public LinkedHashMap(Map<? extends K, ? extends V> m) {  
  22.         super(m);  
  23.         accessOrder = false;  
  24.     }  
  25.     public LinkedHashMap(int initialCapacity,  
  26.                          float loadFactor,  
  27.                          boolean accessOrder) {  
  28.         super(initialCapacity, loadFactor);  
  29.         this.accessOrder = accessOrder;  
  30.     }  
  31.     // 复写父类的init方法,该方法在父类的构造方法里面调用  
  32.     void init() {  
  33.         // 初始化链表头结点header  
  34.         // 该头结点数字无意义。  
  35.         header = new Entry<>(-1nullnullnull);  
  36.         // 双向循环链表  
  37.         header.before = header.after = header;  
  38.     }  
  39.   
  40.     // hashmap里面的该函数的意义是:将原数组table里面的hash表全部搬移到新的数组槽中填充newTable  
  41.     // 由于已经将所有元素用链表连起来了所以是用链表来赋值更加快速  
  42.     //   
  43.     void transfer(HashMap.Entry[] newTable) {  
  44.         int newCapacity = newTable.length;  
  45.         for (Entry<K,V> e = header.after; e != header; e = e.after) {  
  46.             int index = indexFor(e.hash, newCapacity);  
  47.             e.next = newTable[index];  
  48.             newTable[index] = e;  
  49.         }  
  50.     }  
  51.   
  52.     // 判断是否含有某个value  
  53.     // 直接遍历链表会有更好的时间复杂度  
  54.     public boolean containsValue(Object value) {  
  55.         // Overridden to take advantage of faster iterator  
  56.         if (value==null) {  
  57.             for (Entry e = header.after; e != header; e = e.after)  
  58.                 if (e.value==null)  
  59.                     return true;  
  60.         } else {  
  61.             for (Entry e = header.after; e != header; e = e.after)  
  62.                 if (value.equals(e.value))  
  63.                     return true;  
  64.         }  
  65.         return false;  
  66.     }  
  67.   
  68.     public V get(Object key) {  
  69.         Entry<K,V> e = (Entry<K,V>)getEntry(key);  
  70.         if (e == null)  
  71.             return null;  
  72.         // 访问即有可能要改变他在链表中的位置  
  73.         e.recordAccess(this);  
  74.         return e.value;  
  75.     }  
  76.   
  77.     public void clear() {  
  78.         super.clear();  
  79.         header.before = header.after = header;  
  80.     }  
  81.   
  82.     // linkedHashMap的节点  
  83.     private static class Entry<K,V> extends HashMap.Entry<K,V> {  
  84.         // 比起hashmap的节点多了两个指针,一个指向前一个节点一个指向后一个节点  
  85.         Entry<K,V> before, after;  
  86.   
  87.         Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {  
  88.             super(hash, key, value, next);  
  89.         }  
  90.   
  91.         // 从链表中移除本身节点,仅仅指的是修改指针指向  
  92.         private void remove() {  
  93.             before.after = after;  
  94.             after.before = before;  
  95.         }  
  96.   
  97.         // 从链表中添加本节点至existingEntry的前面  
  98.         private void addBefore(Entry<K,V> existingEntry) {  
  99.             after  = existingEntry;  
  100.             before = existingEntry.before;  
  101.             before.after = this;  
  102.             after.before = this;  
  103.         }  
  104.   
  105.        // 覆盖父类的方法  
  106.         void recordAccess(HashMap<K,V> m) {  
  107.             LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;  
  108.             // 如果accessOrder为false什么都不做  
  109.             if (lm.accessOrder) {  
  110.                 lm.modCount++;  
  111.                 // 从链表中移除  
  112.                 remove();  
  113.                 // 将该节点添加到链表header的前面,也就是将其添加到链表末尾(header不变)  
  114.                 addBefore(lm.header);  
  115.                 //前两步其实就是移动该节点到连飙头,因为他刚被访问过  
  116.             }  
  117.         }  
  118.         // 覆盖父类的方法,删除键值对时同时从链表中移除  
  119.         void recordRemoval(HashMap<K,V> m) {  
  120.             remove();  
  121.         }  
  122.     }  
  123.     // 迭代器部分  
  124.     private abstract class LinkedHashIterator<T> implements Iterator<T> {  
  125.         Entry<K,V> nextEntry    = header.after;  
  126.         Entry<K,V> lastReturned = null;  
  127.   
  128.         int expectedModCount = modCount;  
  129.   
  130.         public boolean hasNext() {  
  131.             return nextEntry != header;  
  132.         }  
  133.   
  134.         public void remove() {  
  135.             if (lastReturned == null)  
  136.                 throw new IllegalStateException();  
  137.             if (modCount != expectedModCount)  
  138.                 throw new ConcurrentModificationException();  
  139.   
  140.             LinkedHashMap.this.remove(lastReturned.key);  
  141.             lastReturned = null;  
  142.             expectedModCount = modCount;  
  143.         }  
  144.   
  145.         Entry<K,V> nextEntry() {  
  146.             if (modCount != expectedModCount)  
  147.                 throw new ConcurrentModificationException();  
  148.             if (nextEntry == header)  
  149.                 throw new NoSuchElementException();  
  150.   
  151.             Entry<K,V> e = lastReturned = nextEntry;  
  152.             nextEntry = e.after;  
  153.             return e;  
  154.         }  
  155.     }  
  156.   
  157.     private class KeyIterator extends LinkedHashIterator<K> {  
  158.         public K next() { return nextEntry().getKey(); }  
  159.     }  
  160.   
  161.     private class ValueIterator extends LinkedHashIterator<V> {  
  162.         public V next() { return nextEntry().value; }  
  163.     }  
  164.   
  165.     private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {  
  166.         public Map.Entry<K,V> next() { return nextEntry(); }  
  167.     }  
  168.   
  169.     // These Overrides alter the behavior of superclass view iterator() methods  
  170.     Iterator<K> newKeyIterator()   { return new KeyIterator();   }  
  171.     Iterator<V> newValueIterator() { return new ValueIterator(); }  
  172.     Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }  
  173.   
  174.     // 添加键值对  
  175.     void addEntry(int hash, K key, V value, int bucketIndex) {  
  176.         createEntry(hash, key, value, bucketIndex);  
  177.   
  178.         // Remove eldest entry if instructed, else grow capacity if appropriate  
  179.         Entry<K,V> eldest = header.after;  
  180.         // 判断最旧的,也就是在链表头部的节点是否需要被删除  
  181.         if (removeEldestEntry(eldest)) {  
  182.             removeEntryForKey(eldest.key);  
  183.         } else {  
  184.             if (size >= threshold)  
  185.                 resize(2 * table.length);  
  186.         }  
  187.     }  
  188.   
  189.     // 比起hashmap中的createEntry方法,增加了修改链表  
  190.     void createEntry(int hash, K key, V value, int bucketIndex) {  
  191.         HashMap.Entry<K,V> old = table[bucketIndex];  
  192.         Entry<K,V> e = new Entry<>(hash, key, value, old);  
  193.         table[bucketIndex] = e;  
  194.         // 添加一个键值对时,总要将其链接到维护的链表结尾  
  195.         e.addBefore(header);  
  196.         size++;  
  197.     }  
  198.   
  199.     /******LinkedHashMap暴露的方法,可以用起来实现LRU算法*****/  
  200.     protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {  
  201.         return false;  
  202.     }  
  203. }  

LruCache

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class LruCache<K, V> {  
  2.     // LRC算法底层由LinkedHashMap实现  
  3.     private final LinkedHashMap<K, V> map;  
  4.   
  5.     // 缓存的数量大小,可以使元素个数、字节数等等任何想要的  
  6.     private int size;  
  7.     // 缓存的最大值  
  8.     private int maxSize;  
  9.   
  10.     private int putCount;  
  11.     private int createCount;  
  12.     // 由于缓存空间满了被逐出的次数  
  13.     private int evictionCount;  
  14.     // 从缓存取命中次数  
  15.     private int hitCount;  
  16.     // 为在缓存中找到的次数,即失败次数  
  17.     private int missCount;  
  18.   
  19.     public LruCache(int maxSize) {  
  20.         if (maxSize <= 0) {  
  21.             throw new IllegalArgumentException("maxSize <= 0");  
  22.         }  
  23.         this.maxSize = maxSize;  
  24.         this.map = new LinkedHashMap<K, V>(00.75f, true);  
  25.     }  
  26.   
  27.     //   
  28.     public void resize(int maxSize) {  
  29.         if (maxSize <= 0) {  
  30.             throw new IllegalArgumentException("maxSize <= 0");  
  31.         }  
  32.   
  33.         synchronized (this) {  
  34.             this.maxSize = maxSize;  
  35.         }  
  36.         trimToSize(maxSize);  
  37.     }  
  38.   
  39.     //   
  40.     public final V get(K key) {  
  41.         if (key == null) {  
  42.             // 不允许出现null的键和HashMap不一样  
  43.             throw new NullPointerException("key == null");  
  44.         }  
  45.   
  46.         V mapValue;  
  47.         synchronized (this) {  
  48.             mapValue = map.get(key);  
  49.             if (mapValue != null) {  
  50.                 // 每get成功一次hitCount就自加一次,表示命中次数  
  51.                 hitCount++;  
  52.                 // 如果该键对应的值存在,返回之。  
  53.                 return mapValue;  
  54.             }  
  55.             missCount++;  
  56.         }  
  57.         // 否则,创建该键值对,默认值为null  
  58.         V createdValue = create(key);  
  59.         if (createdValue == null) {  
  60.             return null;  
  61.         }  
  62.   
  63.         synchronized (this) {  
  64.             createCount++;  
  65.             // 将创建的value添加到map  
  66.             mapValue = map.put(key, createdValue);  
  67.   
  68.             if (mapValue != null) {  
  69.                 // mapValue部位空,表示本线程在put之前已经被别的线程put了一个值,即产生了冲突  
  70.                 // 此时我们扔掉刚创建的value,而是使用其他地方产生的value  
  71.                 map.put(key, mapValue);  
  72.             } else {  
  73.                 // 将其放进map中的同时缓存的size增加  
  74.                 size += safeSizeOf(key, createdValue);  
  75.             }  
  76.         }  
  77.   
  78.         if (mapValue != null) {  
  79.             entryRemoved(false, key, createdValue, mapValue);  
  80.             return mapValue;  
  81.         } else {  
  82.             // 根据maxSize修改map,因为有可能由于此次的put操作使得容量超过最大值,具体的修改方式在子函数中  
  83.             trimToSize(maxSize);  
  84.             return createdValue;  
  85.         }  
  86.     }  
  87.   
  88.     // 和get基本一样  
  89.     public final V put(K key, V value) {  
  90.         if (key == null || value == null) {  
  91.             throw new NullPointerException("key == null || value == null");  
  92.         }  
  93.   
  94.         V previous;  
  95.         synchronized (this) {  
  96.             putCount++;  
  97.             size += safeSizeOf(key, value);  
  98.             previous = map.put(key, value);  
  99.             if (previous != null) {  
  100.                 // 返回值部位null,说明之前该键对应的有值,即使替换,因此占用空间减去之前元素  
  101.                 size -= safeSizeOf(key, previous);  
  102.             }  
  103.         }  
  104.   
  105.         if (previous != null) {  
  106.             // 移除元素时调用  
  107.             entryRemoved(false, key, previous, value);  
  108.         }  
  109.   
  110.         trimToSize(maxSize);  
  111.         return previous;  
  112.     }  
  113.   
  114.     // 根据maxSize增删map  
  115.     private void trimToSize(int maxSize) {  
  116.         while (true) {  
  117.             K key;  
  118.             V value;  
  119.             synchronized (this) {  
  120.                 if (size < 0 || (map.isEmpty() && size != 0)) {  
  121.                     throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");  
  122.                 }  
  123.                 // 当前占用的空间小于最大空间时跳出  
  124.                 if (size <= maxSize) {  
  125.                     break;  
  126.                 }  
  127.                 // 否则,取出最近最长未使用的元素,也就是链表最前面的一个  
  128.                 // v5.0.1版本的utils包提供的感觉有问题。  
  129.                 /*Map.Entry<K, V> toEvict = null; 
  130.                 for (Map.Entry<K, V> entry : map.entrySet()) { 
  131.                     // 循环直到最后一个??? 
  132.                     toEvict = entry; 
  133.                 } 
  134.  
  135.                 if (toEvict == null) { 
  136.                     break; 
  137.                 } 
  138.                 */  
  139.                 // V4 包里面的实现https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/util/LruCache.java  
  140.                 Map.Entry<K, V> toEvict = map.entrySet().iterator().next();  
  141.                 // 然而google已经提供的LinkedHashMap中就有一个函数获得eldest的元素,于是有些版本()4.4.2的写法比较好理解  
  142.                 key = toEvict.getKey();  
  143.                 value = toEvict.getValue();  
  144.                 // 移除该元素  
  145.                 map.remove(key);  
  146.                 // 并将占用空间减少  
  147.                 size -= safeSizeOf(key, value);  
  148.                 evictionCount++;  
  149.             }  
  150.   
  151.             entryRemoved(true, key, value, null);  
  152.         }  
  153.     }  
  154.   
  155.     /** 
  156.      * Removes the entry for {@code key} if it exists. 
  157.      * 
  158.      * @return the previous value mapped by {@code key}. 
  159.      */  
  160.     public final V remove(K key) {  
  161.         if (key == null) {  
  162.             throw new NullPointerException("key == null");  
  163.         }  
  164.   
  165.         V previous;  
  166.         synchronized (this) {  
  167.             previous = map.remove(key);  
  168.             if (previous != null) {  
  169.                 size -= safeSizeOf(key, previous);  
  170.             }  
  171.         }  
  172.   
  173.         if (previous != null) {  
  174.             entryRemoved(false, key, previous, null);  
  175.         }  
  176.   
  177.         return previous;  
  178.     }  
  179.   
  180.     // true if the entry is being removed to make space, false if the removal was caused by a put or remove.  
  181.     /****** 可以覆盖进行其他操作 ******/  
  182.     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}  
  183.   
  184.     // 当需要的元素不存在时执行,可以自行覆盖   
  185.     protected V create(K key) {  
  186.         return null;  
  187.     }  
  188.   
  189.     // 返回一个值表示占用的空间,这里做了参数检查  
  190.     private int safeSizeOf(K key, V value) {  
  191.         int result = sizeOf(key, value);  
  192.         if (result < 0) {  
  193.             throw new IllegalStateException("Negative size: " + key + "=" + value);  
  194.         }  
  195.         return result;  
  196.     }  
  197.   
  198.     // 返回一个值表示占用的空间  
  199.     /****** 需要覆盖对不同的元素(键值对)进行不同的处理 ******/  
  200.     protected int sizeOf(K key, V value) {  
  201.         return 1;  
  202.     }  
  203.   
  204.     // 逐出所有的元素,参数为-1,只要里面还有元素就会大于-1,于是要全部移除  
  205.     public final void evictAll() {  
  206.         trimToSize(-1); // -1 will evict 0-sized elements  
  207.     }  
  208.   
  209.     public synchronized final int size() {  
  210.         return size;  
  211.     }  
  212.   
  213.     public synchronized final int maxSize() {  
  214.         return maxSize;  
  215.     }  
  216.   
  217.     public synchronized final int hitCount() {  
  218.         return hitCount;  
  219.     }  
  220.   
  221.     public synchronized final int missCount() {  
  222.         return missCount;  
  223.     }  
  224.   
  225.     public synchronized final int createCount() {  
  226.         return createCount;  
  227.     }  
  228.   
  229.     public synchronized final int putCount() {  
  230.         return putCount;  
  231.     }  
  232.   
  233.     public synchronized final int evictionCount() {  
  234.         return evictionCount;  
  235.     }  
  236.   
  237.     public synchronized final Map<K, V> snapshot() {  
  238.         return new LinkedHashMap<K, V>(map);  
  239.     }  
  240.   
  241.     @Override   
  242.     public synchronized final String toString() {  
  243.         int accesses = hitCount + missCount;  
  244.         int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;  
  245.         return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",  
  246.                 maxSize, hitCount, missCount, hitPercent);  
  247.     }  
  248. }  

android 4.4.2中的LinkedHashMap直接提供了获得最旧元素的方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.      * Returns the eldest entry in the map, or {@code null} if the map is empty. 
  3.      * @hide 
  4.      */  
  5.     public Entry<K, V> eldest() {  
  6.         LinkedEntry<K, V> eldest = header.nxt;  
  7.         return eldest != header ? eldest : null;  
  8.     }  

上面提到的HashMap和LinkedHashMap在jdk的不同版本变化较大,并且和android包中的实现也有一些差异。

以上。

0 0
原创粉丝点击