技术标签: 源码阅读--集合
LinkedHashMap继承自HashMap,它的结构如图所示:
hashmap是无序的,LinkedHashMap是有序的,且默认为插入顺序。
LinkedHashMap通过在HashMap的基础上增加一条双向链表,实现了插入顺序和访问顺序一致。通过对HashMap一些方法的覆盖,例如newNode, replacementNode, replacementTreeNode, newTreeNode,让所有对底层HashMap数据结构修改的同时该链表进行修改,遍历的时候便是遍历这一条有序的链表。需要注意的是get()方法在accessOrder为true的时候也会对底层结构进行修改。
基于get()在accessOrder为true时,会将访问到的元素放到链表的最后的特性,我们可以使用LinkedHashMap实现LRU缓存。
LinkedHashMap和HashMap一样,线程不安全。
另外,leetcode中剑指 Offer 50. 第一个只出现一次的字符 也使用到了这个数据结构。
关于访问顺序和插入顺序, 最开始都是按照插入顺序排列的,而如果设置了accessOrder = true, 则在调用get()方法时,会因为 if(accessOrder == true ) 而调用afterNodeAccess方法来调整顺序。
和hashmap相比,只是在后面增加了if (accessOrder) 代码,目的是实现 LinkedHashMap 按照访问顺序排序。
另外,没有重写getNode()方法,和hashmap一样。
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;
}
就是将一个结点移动到链表尾部
void afterNodeAccess(Node<K,V> e) {
// move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
// 如果e为头结点
if (b == null)
head = a;
else
b.after = a;
// 如果e为尾结点
if (a != null)
a.before = b;
else
last = b;
// 如果链表为空
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
LinkedHashMap没有对put和putVal()进行重写,但是对newNode()进行了重写。
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
// 如果链表为空,则设置p为头部
if (last == null)
head = p;
// 不为空,则放到尾部
else {
p.before = last;
last.after = p;
}
}
LinkedHashMap也没有重写remove()方法,而是重写了removeNode()方法里的afterNodeRemoval()方法
removeNode()方法中只是将HashMap.Entry的next指针删掉, 而 LinkedHashMap.Entry的 before和after指针还没删除,因此这个方法就是断掉双向链表里的after和before
时间复杂度O(1)
public <K, V> Entry<K, V> getHead(LinkedHashMap<K, V> map) {
return map.entrySet().iterator().next();
}
public <K, V> Entry<K, V> getTail(LinkedHashMap<K, V> map) {
Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
Entry<K, V> tail = null;
while (iterator.hasNext()) {
tail = iterator.next();
}
return tail;
}
public static <K, V> Map.Entry<K, V> getTail(LinkedHashMap<K, V> map) throws NoSuchFieldException, IllegalAccessException {
Class<? extends LinkedHashMap> aClass = map.getClass();
Field tail = aClass.getDeclaredField("tail");
tail.setAccessible(true);
return (Map.Entry<K, V>)tail.get(map);
}
文章浏览阅读452次,点赞12次,收藏6次。当要使用模板时,输入"prefix"里自定义的口令,比如上面的口令是vh,输入vh再按enter即可。2.输入 configure user snippets / 配置用户代码片段。3.选择Add browser Breakpoint / 新建全局代码片段文件。4.自定义json文件名,例如vue3.json。将以下内容复制进{}里,保存即可。_vscode 设置 快捷模板
文章浏览阅读889次,点赞11次,收藏16次。本教程从ESP8266-01S固件烧录开始(保姆级教程),详细介绍了如何使用AT指令将ESP8266-01S连接到阿里云物联网平台。对于零基础的用户来说,只要按照教程操作,就能够轻松实现物联网设备的接入和控制。_at+cipsntpcfg
文章浏览阅读338次。第一种,Array.isArray(参数) <script> // Array.isArray(arr) // 函数名- isArray function isArray(arr) { if (Array.isArray(arr)) { console.log('是一个数组'); } else { console.log('不是一个数组'); } } let arr1 = 'a'_封装一个工具函数,传入一个数据,判断是否是数组(异常处理,提升代码健壮性),对传入
文章浏览阅读4.5k次,点赞3次,收藏10次。步骤1:文件位置:Saber/src/mock/menu.js新增菜单模块:步骤2:绑定对应模块路由:(与步骤1中的模块菜单名称对应)在zh.js中添加新增菜单的名称:(与对应路由名称绑定)新建一个页面,路径与步骤1中页面路径对应 (Saber/src/views/util/test.vue),编写页面:完成效果图如下:附上test.vue的完整测试代码:<t..._saber 新增菜单
文章浏览阅读3.3k次,点赞2次,收藏2次。安装完成后,这些包将会被安装在您的 CentOS 系统上。打开终端,使用 root 或具有管理员权限的用户登录。_yum install libssl-dev
文章浏览阅读747次。以前粗略的学习过Matplotlib绘图、Pandas绘图(这里是pandas的常见绘图总结),但是都未深入的去学习过,一遇到问题就翻..._seaborn清晰度
文章浏览阅读76次。先来看个用Python实现的二分查找算法实例import sysdef search2(a,m):low = 0high = len(a) - 1while(low <= high):mid = (low + high)/2midval = a[mid]if midval < m:low = mid + 1elif midval > m:high = mid - 1else:pr..._print(binary_search(0, len(list_num)-1,target, list_num))
文章浏览阅读400次。1、首先要在Gradle 里面设置dependencies2、在UI XML里面添加RecyclerView3、需要编写一个RecyclerView.Adapter 3.1 Adapter里面要编写RecyclerView.Viewholder: 这是RV里面显示的小单元_androidx.recyclerview:recyclerview:1.1.0
文章浏览阅读3.3k次。1、最近想用下CKEditor5 新特性,但发现上传不上去,经调研官网调研如下:1、首先引入jshttps://cdn.ckeditor.com/ckeditor5/17.0.0/classic/ckeditor.js2、html相关代码<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><..._vue+ckeditor上传图片不显示
文章浏览阅读1.9k次,点赞2次,收藏24次。1、在Qt designer中设计界面,包含一个QGroupBox和QWidget:2、导入需要的库:import matplotlibmatplotlib.use("Qt5Agg") # 声明使用QT5from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasimport matplotlib.pyplot as plt3、编写绘图函数:def plot_figure(self, ax_alphalens 图表显示在pyqt中
文章浏览阅读97次。docker 搭建自己的gitlabhttps://www.cnblogs.com/smallstudent/p/5396660.html--privileged=true 容器拥有root权限172.17.0.8--hostname 111.229.235.9 服务器ip地址docker pull gitlab/gitlab-ce:8.7.0-rc3.ce.0mkdir -p /opt/gitlab/config/opt/gitlab/logs/opt..._gitlab 搭建 docker
文章浏览阅读5.7k次,点赞4次,收藏62次。达梦数据库使用安装数据库一、安装规划1、创建用户组、用户、安装目录[root@Kylin10 ~]# groupadd dinstall[root@Kylin10 ~]# useradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdba[root@Kylin10 ~]# passwd dmdba 更改用户 dmdba 的密码 。新的 密码:重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。[root@Kylin10 ~]#_mac安装达梦数据库