LruCache 使用及原理,2024年最新flutter项目

当 accessOrder 为 true 时,这个集合的元素顺序就会是访问顺序,也就是访问了之后就会将这个元素放到集合的最后面。

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.get(1);
map.get(2);

for (Map.Entry < Integer, Integer > entry: map.entrySet()) {
System.out.println(entry.getKey() + “:” + entry.getValue());

}

打印结果:

0:0
3:3
1:1
2:2

以下分别来分析 LruCache 的 put 和 get 方法。

3.1 put 方法分析:

现在以注释的方式来解释该方法的原理。

public final V put(K key, V value) {
// 如果 key 或者 value 为 null,则抛出异常
if (key == null || value == null) {
throw new NullPointerException(“key == null || value == null”);
}

V previous;
synchronized(this) {
// 加入元素的数量,在 putCount() 用到
putCount++;

// 回调用 sizeOf(K key, V value) 方法,这个方法用户自己实现,默认返回 1
size += safeSizeOf(key, value);

// 返回之前关联过这个 key 的值,如果没有关联过则返回 null
previous = map.put(key, value);

if (previous != null) {
// safeSizeOf() 默认返回 1
size -= safeSizeOf(key, previous);
}
}

if (previous != null) {
// 该方法默认方法体为空
entryRemoved(false, key, previous, value);
}

trimToSize(maxSize);

return previous;
}

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!”);
}

// 直到缓存大小 size 小于或等于最大缓存大小 maxSize,则停止循环
if (size <= maxSize) {
break;
}

// 取出 map 中第一个元素
Map.Entry < K, V > toEvict = map.eldest();
if (toEvict == null) {
break;
}

key = toEvict.getKey();
value = toEvict.getValue();
// 删除该元素
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}

entryRemoved(true, key, value, null);
}
}

public Map.Entry<K, V> eldest() {
return head;
}

put() 方法其实重点就在于 trimToSize() 方法里面,这个方法的作用就是判断加入元素后是否超过最大缓存数,如果超过就清除掉最少使用的元素。

3.2 get 方法分析

public final V get(K key) {
if (key == null) {
throw new NullPointerException(“key == null”);
}

V mapValue;
synchronized(this) {
// 获取 Value
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}


}

// LinkedHashMap get 方法
public V get(Object key) {
Node < K, V > e;
if ((e = getNode(hash(key), key)) == null) return null;
if (accessOrder) afterNodeAccess(e);
return e.value;
}

static class Node < K, V > implements Map.Entry < K, V > {
final int hash;
final K key;
V value;
Node < K, V > next;

Node(int hash, K key, V value, Node < K, V > next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}

public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final String toString() {
return key + “=” + value;
}

public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}

public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}

public final boolean equals(Object o) {
if (o == this) return true;
if (o instanceof Map.Entry) {
Map.Entry <? , ?> e = (Map.Entry <? , ?> ) o;
if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true;
}
return false;
}
}

static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}

get() 方法其实最关键就是 afterNodeAccess(),现在重点分析:

3.2.1 关键方法 afterNodeAccess()

// 这个方法的作用就是将刚访问过的元素放到集合的最后一位
void afterNodeAccess(Node < K, V > e) {
LinkedHashMap.Entry < K, V > last;
if (accessOrder && (last = tail) != e) {
// 将 e 转换成 LinkedHashMap.Entry
// b 就是这个节点之前的节点
// a 就是这个节点之后的节点
LinkedHashMap.Entry < K, V > p = (LinkedHashMap.Entry < K, V > ) e, b = p.before, a = p.after;

// 将这个节点之后的节点置为 null
p.after = null;

// b 为 null,则代表这个节点是第一个节点,将它后面的节点置为第一个节点
if (b == null) head = a;
// 如果不是,则将 a 上前移动一位
else b.after = a;
// 如果 a 不为 null,则将 a 节点的元素变为 b
if (a != null) a.before = b;
else last = b;
if (last == null) head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}

链表情况可能性图示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以下来分析情况一。

3.1.2.1 情况一:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1. p.after = null;

图示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. b.after = a; a.before = b;

图示:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3. p.before = last; last.after = p;

图示:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:

❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞

希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。

下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。

**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)

  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

  • Flutter进阶学习全套手册

  • Flutter进阶学习全套视频

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
外链图片转存中…(img-rMopUSqs-1712800108163)]

  • Flutter进阶学习全套视频

[外链图片转存中…(img-r3QjRpaO-1712800108163)]

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-pa6lqgvN-1712800108163)]

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值