总结:
1.LinkedHashMap是继承于HashMap,是基于数组 和 双向链表来实现的。
2.HashMap无序;LinkedHashMap有序,可分为插入顺序 和 访问顺序两种。如果是访问顺序,那put 和 get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除 再插入)
3.LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。
4.LinkedHashMap是线程不安全的,HashMap也是线程不安全的。
LinkedHashMap存储数据是有序的,分为两种:插入顺序 和 访问顺序。
空参构造
public LinkedHashMap() {
// 调用HashMap的构造方法,其实就是初始化Entry[] table
super();
// 这里是指是否基于访问排序,默认为false
accessOrder = false;
}
带参构造
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
其中accessOrder设置为false,则为插入顺序,否则为访问顺序。
举个例子:
accessOrder为true
public static void main(String[] args){
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>(0, 0.75f, true);
map.put(0, 0);
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
map.get(1);
map.get(2);
for(Map.Entry<Integer, Integer> entry: map.entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
最终输出结果是
0:0
3:3
4:4
1:1
2:2
也就是说最近访问的被放到了头部,最后输出,这正好满足LRU缓存算法的思想。LruCache的实现,正是利用了LinkedHashMap的这种数据结构。
android中的缓存策略
一般来说,缓存策略主要包含缓存的添加、获取 和 删除这三类操作。添加和获取缓存比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存 还是硬盘缓存,它们的缓存大小都是有限的。当缓存满了以后,再想添加缓存,就需要删除一些旧的缓存 并添加新的缓存。
因此,LRU(Least Recently Used)缓存算法应运而生,LRU是近期最少使用的算法,它的核心思想是当缓存满时,会优先删除那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LruCache 和 DiskLruCache,分别用于实现内存缓存 和 硬盘缓存,其核心思想都是LRU缓存算法。
LruCache的使用
使用很简单,以缓存图片为例,只需两步
1)设置LruCache缓存的大小,一般为当前进程可用容量的1/8.
2)重写sizeOf方法,计算出要缓存的每张图片的大小,默认返回图片的数量。
int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory/8;
LruCache mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value){
return value.getRowBytes() * value.getHeight() / 1024;
}
};
LruCache的实现原理
核心思想就是要维护一个缓存对象列表,其中对象列表的排列方式是按照访问顺序实现的,即一直没被访问的对象,将放在队尾,即将被淘汰;而最近访问的对象将放在对头,最后被淘汰。
那么这个缓存队列由谁维护呢,答案是:LinkedHashMap。
因为双向链表结构 可以实现访问顺序 和 插入顺序,使得LinkedHashMap中的键值对按照一定的顺序排列起来。
总结就是:
LruCache中维护了一个LinkedHashMap集合,该LinkedHashMap是以访问顺序排序的。当调用put方法时,就会在集合中添加元素,并调用trimToSize()判断缓存是否已满。如果满了就用LinkedHashMap的迭代器删除队尾元素,即最近最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。