LinkedList源码学习
链表数据结构
当前节点会保存上一个、下一个节点。 参见 LinkedList的Node类
实现:
1. 内部链表的方式。
1.1 添加元素。追加的方式,创建一个新的节点[Node],用最后一个节点关联新的节点。
1.2 删除元素
1.2.1 通过对象删除。遍历链表,删除第一个匹配的对象
修改链表关联结构
2. 内部是同步[modCount]
2.1 LinkedList数据结构变化的时候,都会将modCount++。
2.2 采用Iterator遍历的元素, next()会去检查集合是否被修改[checkForComodification],如果集合变更会抛出异常
类似于数据库层面的 乐观锁 机制。 可以通过 Iterator的api去删除元素
3. 数组结构,内部存储数据是有序的,并且数据可以为null
源码实现
package xin.rtime.collections.list;import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.ListIterator; import java.util.NoSuchElementException;// 链表的源码实现 public class LinkedList<E> {transient int size = 0; // 当前链表的size transient Node<E> first; // 首节点 transient Node<E> last; // 尾节点private int modCount = 0; // 结构修改次数// 添加节点public boolean add(E e) {linkLast(e);return true;}// 删除节点public boolean remove(Object o) {if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null) {unlink(x);return true;}}} else {for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) { // equals unlink(x);return true;}}}return false;}// 获取节点public E get(int index) {checkElementIndex(index); // 检查元素Index是否存在 , 不存在会抛出数组越界return node(index).item;}// 获取链表sizepublic int size() {return size;}public Iterator<E> iterator() {return listIterator();}public ListIterator<E> listIterator() {return listIterator(0);}Node<E> node(int index) {// assert isElementIndex(index);if (index < (size >> 1)) { // 当前index 小于 当前一半容量的 sizeNode<E> x = first; // 当前节点 等于 首节点for (int i = 0; i < index; i++) // 遍历 index -1 次x = x.next; // x 等于当前节点的下一个节点return x;} else { // 大于Node<E> x = last;for (int i = size - 1; i > index; i--) // 从尾部开始遍历x = x.prev; // x 等于当前节点的上一个节点return x;}}private void checkElementIndex(int index) {if (!isElementIndex(index)) // 节点index是否在链表的容量范围内throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}private boolean isElementIndex(int index) {return index >= 0 && index < size;}private String outOfBoundsMsg(int index) {return "Index: "+index+", Size: "+size;}// 获得首个节点值public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;}// 获得尾部节点值public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;}// 获得所有节点值public Object[] toArray() {Object[] result = new Object[size];int i = 0;for (Node<E> x = first; x != null; x = x.next)result[i++] = x.item;return result;}public ListIterator<E> listIterator(int index) {checkPositionIndex(index);return new ListItr(index);}private void checkPositionIndex(int index) {if (!isPositionIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}// 判断当前节点index是否存在private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}private class ListItr implements ListIterator<E> {private Node<E> lastReturned = null; // 返回的节点private Node<E> next; // 下个节点private int nextIndex; // 下个节点 下标private int expectedModCount = modCount; // 预期的修改次数 = 等于遍历时的修改次数 ListItr(int index) {// assert isPositionIndex(index);next = (index == size) ? null : node(index);nextIndex = index;}public boolean hasNext() {return nextIndex < size;}public E next() {checkForComodification(); // 校验当前链表是否被改动if (!hasNext())throw new NoSuchElementException();lastReturned = next;next = next.next;nextIndex++;return lastReturned.item;}public boolean hasPrevious() {return nextIndex > 0;}public E previous() {checkForComodification(); // 校验当前链表是否被改动if (!hasPrevious())throw new NoSuchElementException();lastReturned = next = (next == null) ? last : next.prev;nextIndex--;return lastReturned.item;}public int nextIndex() {return nextIndex;}public int previousIndex() {return nextIndex - 1;}public void remove() {checkForComodification(); // 校验当前链表是否被改动if (lastReturned == null)throw new IllegalStateException();Node<E> lastNext = lastReturned.next;unlink(lastReturned); // 剔除节点if (next == lastReturned)next = lastNext;elsenextIndex--;lastReturned = null;expectedModCount++;}// 当前节点设置值public void set(E e) {if (lastReturned == null)throw new IllegalStateException();checkForComodification();lastReturned.item = e; }public void add(E e) {checkForComodification();lastReturned = null;if (next == null) // 下一个节点为nulllinkLast(e); // 在尾部插入elselinkBefore(e, next); // 在指定节点之前插入nextIndex++;expectedModCount++;}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}private E unlink(Node<E> x) {final E element = x.item; // 当前元素final Node<E> next = x.next; // 下一个节点 final Node<E> prev = x.prev; // 上一个节点if (prev == null) { // 上一个节点为空first = next; // 首节点 = 当前节点下一个节点} else { // 不为空prev.next = next; // 上一个节点的下一个节点 等于 当前节点的 下一个节点x.prev = null; // 当前节点的上一个节点置为null gc回收 }if (next == null) { // 下一个节点为空last = prev; // 最后节点 = 当前节点的上一个节点} else { // 不为空 next.prev = prev; // 上一个节点的上一个节点 等于 当前节点的上一个节点x.next = null; // 当前节点的下一个节点置为null gc回收 }x.item = null; // 当前元素置为null gc回收size--; // 长度 + 1modCount++; // 修改次数+1return element;}// 在链表的尾部插入节点void linkLast(E e) {final Node<E> l = last; // 最后一个元素final Node<E> newNode = new Node<>(l, e, null); // 上一个元素,当前元素,nulllast = newNode; // 最后一个节点等新建的节点if (l == null) // 如果最后一个节点为空first = newNode; // 出现一个情况: 当链表为空的时候 , first 和 last 都为 newNodeelsel.next = newNode; //最后节点的下一个节点,等于当前节点size++; // 链表长度+1modCount++; // 修改次数+1 }// 在指定节点添加上一个节点void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;}// 链表节点private static class Node<E> {E item;Node<E> next; // 下一个元素Node<E> prev; // 上一个元素 Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}} }
转载于:https://www.cnblogs.com/LuisYang/p/10034601.html
LinkedList源码学习相关推荐
- JDK源码学习之Arraylist与LinkedList
ArrayList和LinkedList是我们在开发过程中常用的两种集合类,本文将从底层源码实现对其进行简单介绍. 下图是Java集合类所涉及的类图. 一.ArrayList 从上面的集合类图可以看出 ...
- 从面试角度分析LinkedList源码
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 注:本系列文章中用到的jdk版本均为java8 Linke ...
- 集合框架源码学习之HashMap(JDK1.8)
目录: 0-1. 简介 0-2. 内部结构分析 0-2-1. JDK18之前 0-2-2. JDK18之后 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. put方法 0 ...
- Java 集合系列(4): LinkedList源码深入解析1
戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 概要 前面,我们已经学习了ArrayList,并了解了fail-fast ...
- 【Android 源码学习】SharedPreferences 源码学习
第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...
- 【博学谷学习记录】超强总结,用心分享 | 架构师 Mybatis源码学习总结
Mybatis源码学习 文章目录 Mybatis源码学习 一.Mybatis架构设计 二.源码剖析 1.如何解析的全局配置文件 解析配置文件源码流程 2.如何解析的映射配置文件 Select inse ...
- Hadoop HDFS源码学习之NameNode部分
NameNode源码学习 文章目录 NameNode源码学习 一.文件系统目录树(第一关系) 2.1 INode相关类 2.2 快照特性的实现 2.3 FSEditLog类 2.4 FSImage类 ...
- Shiro源码学习之二
接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...
- Shiro源码学习之一
一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...
最新文章
- Linux: debian/ubuntu下安装和使用Java 8
- Linux下查找文件方法
- 推荐算法矩阵分解实战——keras算法练习
- Android可输入的下拉框,android 可编辑的下拉框 Demo
- 2020-2021年度第二届全国大学生算法设计与编程挑战赛(春季赛)【部分题题解】
- Android 编译系统分析(一)
- video和dvd audio区别:
- Codeforces Round #626 (Div. 2) D. Present 按位贡献 + 快排新姿势
- 如果__name__ =='__main__':在Python中怎么办?
- 一点等于多少厘米_马桶知识介绍,你了解马桶多少
- Jackson第一篇【JSON字符串、实体之间的相互转换】
- java手机音乐文件夹,从原始文件夹打开音乐文件,使用Android上的意图在设备的默认应用程序上播放...
- [材料力学]弯扭组合梁实验报告
- [ JAVA编程 ] double类型计算精度丢失问题及解决方法
- windows中的凭据管理
- 安捷伦34401A六位半万用表
- 微积分小糊涂源于微积分大糊涂
- 你的Web系统真的安全吗?
- 利用一般处理程序处理头像的浏览和更新
- 扫描电子显微镜基本构造
热门文章
- ajax解析json中的对象数组对象,在JQuery中检索json数组后获取json对象Ajax
- 计划任务文件 linux,Linux之任务计划
- 背计算机专业英语词汇,计算机专业英语词汇1500词(五)
- sgm3157功能_SGM3157_SGM3157供应商_价格_Datasheet_pdf资料-IC资料网
- 如何使用explain进行SQL语句调优
- android web3j 代币查询_使用Web3.js查询以太币和代币余额以及转账
- ❤️六W字《计算机基础知识》(四)(建议收藏)❤️
- ORACLE 12C采坑之 ORA-12541:TNS:无监听程序
- mysql for update场景_一个mysql死锁场景实例分析
- ntext在mysql_varchar和text说不清的那些事