LinkedList源码解读
1.背景
这一节来带着大家一起阅读LinkedList的源码
2.先来认识一下什么是双向链表
示例图:
代码:

package com.ldp.collection.demo01; import org.junit.Test; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 04/05 6:03 * @description */ public class Test04LinkedList { /** * 双向链表理解 */ @Test public void test01() { // 定义三个节点 Node node1 = new Node("张无忌"); Node node2 = new Node("赵敏"); Node node3 = new Node("周芷若"); // 将节点node1->node2->node3 依次使用双向链表链接 // node1->node2 node1.next = node2; // 节点1的下一个元素是节点2 node2.prev = node1; // 节点2的上一个元素是节点1 // node2->node3 node2.next = node3; // 节点2的下一个元素是节点3 node3.prev = node2; // 节点3的上一个元素是节点2 Node first = node1;// 头节点为node1 Node last = node3; // 尾节点为node3 printNode(first, true); // 从头到尾 printNode(last, false); // 从尾到头遍历 System.out.println("尾部添加一个元素:小昭"); Node node4 = new Node("小昭"); last.next = node4; node4.prev = last; last = node4; printNode(first, true); System.out.println("头部添加一个元素:张三丰"); Node node5 = new Node("张三丰"); node5.next = first; first.prev = node5; first = node5; printNode(first, true); // 在中间添加一个节点 System.out.println("在node1[张无忌]与node2[赵敏]之前添加一个:node6[金毛狮王]"); Node node6 = new Node("金毛狮王"); node1.next = node6; // 张无忌的下一个是金毛狮王 node6.prev = node1; // 金毛狮王的上一个是张无忌 node6.next = node2; // 金毛狮王的下一个是赵敏 node2.prev = node6; // 赵敏的上一个是金毛狮王 printNode(first, true); } /** * 节点遍历 * * @param node 遍历的节点 * @param flag flag=true表示从头到尾遍历,flag=false从尾到头遍历 */ public void printNode(Node node, boolean flag) { System.out.println("节点遍历开始......"); while (true) { if (node == null) break; System.out.println("当前节点数据为:" + node.item); if (flag) { node = node.next; // 指向下一个节点,从头到尾遍历 } else { node = node.prev; // 指向上一个节点,从尾到头遍历 } } System.out.println(" "); } } class Node { Node prev; // 上一个节点 Object item; // 数据 Node next;// 下一个节点 public Node(Object item) { this.item = item; } }
3.源码解读
代码中重点解读了add方法,与remove方法,get方法

package com.ldp.collection.my; import java.util.*; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 04/05 6:51 * @description */ public class MyLinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { transient int size = 0; transient Node<E> first; transient Node<E> last; public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Node<E> l = last;// 当前最后一个节点为 l final Node<E> newNode = new Node<>(l, e, null);// 新建立一个节点,上一为l,下一个为null last = newNode;// 设置最后一个节点为 新的节点 if (l == null) // 最后一个节点为空(首次添加节点的时候),newNode是第一个节点也是最后一个节点 first = newNode; else l.next = newNode;// 如果当前的最后一个节点不为空,那么它的下一个节点为newNode size++; // 节点数累加1 modCount++; // 修改次数累加1 } public E get(int index) { checkElementIndex(index); // 检查下标是否越界 return node(index).item;// 根据下标取节点 } /** * 检查下标是否越界 */ private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: " + index + ", Size: " + size(); } private boolean isElementIndex(int index) { return index >= 0 && index < size; } /** * 根据下标删除节点 * * @param index * @return */ public E remove(int index) { checkElementIndex(index);// 判断下标是否越界 return unlink(node(index)); } /** * 删除当前节点 * * @param x * @return */ E unlink(Node<E> x) { final E element = x.item;// x节点的元素值 final Node<E> next = x.next; // x节点的下一个节点 final Node<E> prev = x.prev; // x节点的上一个节点 // 处理x节点的下一个节点的下一个节点 if (prev == null) {// x节点的上一个节点为null,说明x节点就是第一个节点,删除x节点后,x的下一个节点为第一个节点 first = next; } else { prev.next = next; x.prev = null;// 切断x的上一个节点 } // 处理x节点的上一个节点的上一个节点 if (next == null) {// x的下一个节点为null,说明x节点是最后一个节点,删除x节点后,x的上一个节点为最后一个节点 last = prev; } else { next.prev = prev; x.next = null;// 切断x的下一个节点 } x.item = null; // x节点的数据设置为空 size--;// 长度减一 modCount++; // 修改次数加一 return element; // 返回删除的元素 } /** * 根据下标取出节点 * * @param index * @return */ Node<E> node(int index) { if (index < (size >> 1)) { // size >> 1 表示长度除以2,如果下标小于长度的1/2则从头开始遍历 Node<E> x = first; for (int i = 0; i < index; i++)// 循环遍历一直取下一个,直到指定的下标 x = x.next;// 下个表示从头遍历 return x; } else { // 下标不小于长度的1/2则从尾开始遍历 Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; // 上一个表示从尾遍历 return x; } } 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; } } @Override public ListIterator<E> listIterator(int index) { return null; } @Override public void addFirst(E e) { } @Override public void addLast(E e) { } @Override public boolean offerFirst(E e) { return false; } @Override public boolean offerLast(E e) { return false; } @Override public E removeFirst() { return null; } @Override public E removeLast() { return null; } @Override public E pollFirst() { return null; } @Override public E pollLast() { return null; } @Override public E getFirst() { return null; } @Override public E getLast() { return null; } @Override public E peekFirst() { return null; } @Override public E peekLast() { return null; } @Override public boolean removeFirstOccurrence(Object o) { return false; } @Override public boolean removeLastOccurrence(Object o) { return false; } @Override public boolean offer(E e) { return false; } @Override public E remove() { return null; } @Override public E poll() { return null; } @Override public E element() { return null; } @Override public E peek() { return null; } @Override public void push(E e) { } @Override public E pop() { return null; } @Override public int size() { return size; } @Override public Iterator<E> descendingIterator() { return null; } }
测试代码:
@Test public void test02() { // LinkedList list = new LinkedList(); MyLinkedList list = new MyLinkedList(); list.add("张无忌"); list.add("赵敏"); list.add("张无忌"); list.add("周芷若"); System.out.println("size=" + list.size()); System.out.println("获取index=3的元素"+list.get(3));//周芷若 // System.out.println("list=" + list);// 因这个方法没有重写listIterator(int index),不能使用迭代器 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("删除后index=3的元素"); list.remove(3); System.out.println("删除后的list"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人