那就有必要来看看LruCache源代码了 里面有一个重要的数据结构LinkedHashMap。具体讲解在这里(http://blog.csdn.net/lxj1137800599/article/details/54974988) 在此总结一下用法: 1.添加一个数据。先找到数组中对应的index,然后把数据放到链表的最后位置。由于是双向链表,那么就等于放在header.prv 2.获取一个数据。先找到数组中对应的index,然后找到数据所在的位置。如果是按照读取顺序来排序的,那么还要将这个节点放到双向链表的最后一位(这个特性,可以实现LRU算法)
public class LruCache<K, V> {
//map用来存储外界的缓存对象
private final LinkedHashMap<K, V> map;
// 构造函数
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
//设置accessOrder为true,按照读取顺序来存储缓存
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
//获取一个缓存对象
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
//设置为true了,还要将这个节点放到双向链表的最后一位
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
/*
* Attempt to create a value. This may take a long time, and the map
* may be different when create() returns. If a conflicting value was
* added to the map while create() was working, we leave that value in
* the map and release the created value.
*/
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
//试着添加一个新值
//如果是要添加数据的,mapValue=null,size扩大然后trimToSize
//如果是替换数据,mapValue!=null
mapValue = map.put(key, createdValue);
if (mapValue != null) {
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
//添加一个缓存对象
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
// previous = null表示新添加的缓存之前未存在过
// previous != null表示之前已存在数据
if (previous != null) {
// 之前已有数据,那么size再减回去
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);
return previous;
}
//重点在这里****************************************
//如果超出最大容量,那就去掉header.next
//由于新添加的数据已经跑到header.prv去了,所以删除的必定是最近最少使用的
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
}
总结如下:accessOrder设置为true。 当添加缓存时,先添加数据,再把对应的entry挪到双向链表的末尾。如果size超过最大值,就删除header.next 当获取缓存时,先获取数据。由于设置为true,那么也会将对应的entry挪到双向链表的末尾