LinkedList实现原理(JDK1.8)

尚硅谷-深入java8的集合4:LinkedHashMap的实现原理.pdf 本教程特点: 1.更适合零基础学员: ·自Java语言起源始,循序渐进,知识点剖析细致且每章配备大量随堂练习,让你步步为营,学得透彻、练得明白 ·拒绝晦涩难懂的呆板教学,宋老师语言生动幽默,举例形象生动深入浅出,迅速让你把握问题本质,四两拨千斤 2.课程内容推陈出新: ·基于JDK 11,将Java8、Java9、Java10、Java11新特性一网打尽 ·课程中,Eclipse和IDEA这两种企业一线开发环境都使用到了 3.技术讲解更深入、更全面: ·课程共30天,715个知识视频小节,涉及主流Java使用的方方面面,全而不冗余 ·全程内容涵盖数据结构、设计模式、JVM内存结构等深度技术 ·企业级笔试面试题目深入源码级讲解,拒绝死记硬背 4.代码量更大、案例更丰富、更贴近实战: ·Java语言基础阶段:12720行代码,Java语言高级阶段:11684行代码 ·课堂实战项目3套,课后实战项目2套 ·近百道企业面试真题精讲精练、极具实战性 立即下载

LinkedList实现原理(JDK1.8)

LinkedList底层采用双向链表,如果对链表这种结构比较熟悉的话,那LinkedList的实现原理看明白就相当容易。

链表通过“指针”将一组零散的内存块串联起来使用,每一个元素(节点)通过指针指向它的下一个元素,最后一个节点的下一个指向为null,而双向链表就是除头节点的每一个元素都有指针同时再指向它的上一个元素。链表不同于数组,由于其地址的不连续,且元素占用大小的不确定,所以没法根据地址直接取值,获取元素时需要遍历访问,而双向链表相比于单向链表,一定程度上占用了额外的内存,但支持了双向遍历,加快了元素索取。

public class LinkedList<E> extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList继承于AbstractSequentialList抽象类,AbstractSequentialList又继承于AbstractList,最终实现了List的接口,所以LinkedList支持List集合的一些常规操作,但同时LinkedList又实现了Queue接口,所以LinkedList也支持队列的一些使用,例如peek、pop等。

1.成员变量
    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

LinkedList的主要成员变量就3个,大小size、头结点first、尾节点last,这也符合双向链表的特点,根据头或者尾部节点就可以遍历整个链表。至于节点类型,则是内部类Node。

    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;
        }
    }

Node类就简简单单三个属性,也即双向链表节点必须的3个要素,当前节点数据item,下一节点next和上一节点prev。

2.构造方法
    public LinkedList() {
    }

    public LinkedList(Collection<? extends E> c) {
        this();
        // 添加所有元素
        addAll(c);
    }

LinkedList主要就两个构造方法,一个无参的构造,什么也没做,另一个接受集合的构造,该方法初始化了LinkedList对象并添加了所有集合c的元素。

至于addAll方法,我们后面再看。

LinkedList因为基于链表,所以不需要提前申请内存大小,也就不存在初始化指定容量大小,因而LinkedList是没有初始化指定size的构造方法的。

3.添加元素
3.1.尾部添加

LinkedList的添加方法有很多,首先最简单也是最常用的尾部添加。

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

主要逻辑就是linkLast(E e) 了。

    void linkLast(E e) {
        final Node<E> l = last;
        // 构造新的节点,上一节点指向原来的last
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size  ;
        // 操作数自增
        modCount  ;
    }

尾部添加,就是构造新的节点newNode,并将改节点的上一节点prev指向原来的last,同时改节点为新的last节点。l == null判断是否当前是第一次添加,如果 l 为 null,则newNode同时也是头结点,当前集合中仅有newNode一个元素,不为null时,因为双向链表,所有 l 的下一个节点next指向了newNode。

最后就是大小size自增与操作计数modCount的自增,尾部添加元素就完成了。

尾部操作除了add,还有个addLast(E e) 方法,两者除了返回值不一样,没有任何差别了,都是调用的linkLast方法。

    public void addLast(E e) {
        linkLast(e);
    }
3.2.中间添加
    public void add(int index, E element) {
        // 范围检查
        checkPositionIndex(index);
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

对于中间添加,需要首先进行范围检查,即保证插入位置index在[0, size]之间,否则抛出数组越界异常IndexOutOfBoundsException,呃……数组越界……

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

如果index == size,其实就是尾部插入,所以调用了linkLast,这个刚刚尾部插入已经说过。

如果index < size,中间插入的时候,需要分两步:

  1. node(int index)方法获取到index位置的元素succ
  2. linkBefore(E e, Node succ)将需要插入的元素element连接到succ后面

node方法是一个频繁被调用的方法,LinkedList 的很多操作都依赖于该方法查找到对应的元素。根据索引 index 获取元素时,因为双向链表的支持前后遍历,所以进行了位置判断,index < (size >> 1),与中间位置比较,靠前则前序遍历,否则后序遍历。

    Node<E> node(int index) {
        // assert isElementIndex(index);
        if (index < (size >> 1)) { //前序遍历
            Node<E> x = first;
            for (int i = 0; i < index; i  )
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

遍历逻辑很简单,循环到index上一个节点(后序则是下一个)位置,获取next(后序使用prev)返回index位置对应的节点Node对象succ。

    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;
        else
            pred.next = newNode;
        size  ;
        modCount  ;
    }

linkBefore和linkLast几乎完全一样,除了一个是添加到 last 节点后,一个是添加到 succ 节点后。

对于中间插入,如果index为0时,其实就是头部插入,这个时候比不用调用node方法去查找元素了,所以LinkedList也提供了一个addFirst(E e)方法。

    public void addFirst(E e) {
        linkFirst(e);
    }

    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size  ;
        modCount  ;
    }
3.3.批量插入

LinkedList提供尾部批量插入和中间批量插入,但内部实现其实都是调用的addAll(int index, Collection<? extends E> c)。

    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        // 范围校验
        checkPositionIndex(index);
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;
        // succ是index位置元素,pred是index的前一个元素
        Node<E> pred, succ;
        if (index == size) { // 尾部插入
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }
		// 循环插入
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }
        // 衔接处理
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        
        size  = numNew;
        modCount  ;
        return true;
    }

addAll(int index, Collection<? extends E> c)方法初一看,好像有些复杂,但明白其原理后,就变得清晰多了。链表插入就如同接水管,先从某一个位置断开水管,然后用接口连接上需要接入的部分。这个方法里,关键的是两个Node对象pred, 和 succ,succ 是index位置元素,pred是index的前一个元素(变动)。

特殊情况 index == size 时,即尾部插入,所以succ 就是null了,而 pred则为尾部节点last。

然后就是循环赋值了,在循环中构造node节点,类似于linkLast。

最后的是衔接处理,如果尾部插入的话,那pred就是尾部节点了(循环赋值时有pred = newNode处理),所以只需要指定last = pred。而中间插入,指明 pred.next = succ、succ.prev = pred即将index位置与新的前一个元素绑定到一起。

4.查找元素

LinkedList 除了提供通用的 get,因为其属性中含有 first 和 last 节点,也提供了 getFirst 和 getLast 方法。

    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;
    }

对于getFirst 和 getLast,因为是成员变量,省去了查找的过程,直接返回其节点 item 即可。

    public E get(int index) {
        // 范围校验
        checkElementIndex(index);
        // node方法获取节点
        return node(index).item;
    }

而通过指针的获取,主要就是调用node方法找对index对应的节点,node方法前面已经讲过,不再累述。

5.修改元素

对于LinkedList集合中元素的修改,需要先查找到该元素,然后更改其Node节点数据item即可。

    public E set(int index, E element) {
        // 范围检查
        checkElementIndex(index);
        // 获取index对应位置的Node对象
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }
6.删除元素

LinkedList提供了很多种删除元素的方法,但是内部实现逻辑基本都相同,即找到对应的Node节点,然后将指向该节点的指向替换。

6.1.根据索引移除

我们先来看看根据索引的remove(int index)方法。

    public E remove(int index) {
        // 范围检查
        checkElementIndex(index);
        // 解除节点指针连接
        return unlink(node(index));
    }

删除时的范围检查就不说了,node方法也不再多提,删除的主要逻辑就是unlink(Node x)方法。

    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        // 下一节点
        final Node<E> next = x.next;
        // 前一节点
        final Node<E> prev = x.prev;
		// 前一节点prev存在则将prev的下一节点指向next,不存在则当前移除节点其实就是头结点,next就是新的first
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
		// 下一节点next存在,则将next上一节点指向prev,不存在则说明当前移除的是未节点
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
		// 触发GC工作
        x.item = null;
        size--;
        // 操作计数器自增
        modCount  ;
        return element;
    }

整个unlink方法就是个标准的双向链表删除操作,三个节点prev,x,next,删除x 其实就是将 prev指向next,并next指向prev,只是其中多了一些特殊的判断。

看了按索引删除的remove,再来看另外两个特例removeFirst 和 removeLast。

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        // 操作计数器自增
        modCount  ;
        return element;
    }

unlinkFirst就是个简化版的unlink方法,因为只用处理头结点,下一个节点next存在就将next作为新的first。

同理removeLast也是类似,这里各位看官自行进行体会。

    public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }

    private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount  ;
        return element;
    }

而LinkedList还有个无参的remove,这个是Deque接口定义的,实现也就是调用的removeFirst。

    public E remove() {
        return removeFirst();
    }
6.2.根据元素移除

根据元素移除其实和根据索引移除没有太大差别,只不过找到对应节点的方式发生了变化。

    public boolean remove(Object o) {
        // 判断元素是否为null,因为LinkedList支持添加null
        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)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

可以看到,无论元素是否为null,都是先找到该节点,然后调用了unlink方法。

因为支持双向遍历的特性,LinkedList很人性的提供了前序删除和后序删除的方法,即removeFirstOccurrence与removeLastOccurrence。

    public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }

    public boolean removeLastOccurrence(Object o) {
        if (o == null) {
            // 后序遍历
            for (Node<E> x = last; x != null; x = x.prev) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            // 后序遍历
            for (Node<E> x = last; x != null; x = x.prev) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

这两个方法没什么玄幻的,removeLastOccurrence只是反序遍历了集合。

6.3.批量删除

在LinkedList类中,并没有removeAll方法,因为他未对其进行重写,而是使用了父类AbstractCollection的

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        boolean modified = false;
        // 使用迭代器
        Iterator<?> it = iterator();
        while (it.hasNext()) {
            if (c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

removeAll的实现原理其实就是迭代删除,迭代器的获取方法iterator()在AbstractCollection类中只是个抽象方法,AbstractList类有其实现,但AbstractSequentialList类中覆写该方法。

    public Iterator<E> iterator() {
        return listIterator();
    }

iterator方法会调用listIterator(),这个方法实现在AbstractList类中,他调用了listIterator(int index)方法,但LinkedList重写了该方法,所以兜兜转转最终还是回到了LinkedList中。

    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }

这里ListItr对象是LinkedList的内部类。

    private class ListItr implements ListIterator<E> {
        private Node<E> lastReturned;
        private Node<E> next;
        private int nextIndex;
        // 期待计数器
        private int expectedModCount = modCount;

ListItr在初始化的时候,会将操作计数器modCount赋值给expectedModCount,而之后的每次remove方法,都会校验expectedModCount与modCount是否相等,否则会抛出异常。

ListItr的remove方法,每次调用后,都将expectedModCount自增,已达到和unlink中modCount 的同步,从而使得modCount == expectedModCount 一直成立,这也是为什么我们循环删除LinkedList元素时需要使用其迭代器的remove方法。

        public void remove() {
            // 校验modCount
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            // unlink删除节点逻辑,该方法中有modCount  ;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            // expectedModCount自增
            expectedModCount  ;
        }

        final void checkForComodification() {
            // expectedModCount与modCount必须相等
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
实测338MB/s!FPGA与CYUSB3014的Slave FIFO模式实战避坑(附完整固件与源码) 本文详细介绍了FPGA与CYUSB3014在Slave FIFO模式下实现338MB/s高速数据传输的实战经验。通过优化硬件设计、固件配置和GPIF II接口设置,解决了USB3.0双向通信中的关键性能瓶颈,并提供了完整的固件与源码参考。 阅读详情

相关推荐

[arcgis插件]在批量出图时,如何把图层属性表以动态表格的形式插入到布局页面

在批量出图时,如何把图层属性表以动态表格的形式插入到布局页面。

坐听风雨 4563

java list jdk1.8_Java集合:LinkedList (JDK1.8 源码解读)

LinkedList介绍还是和ArrayList同样的套路,顾名思义,linked,那必然是基于链表实现的,链表是一种线性的储存结构,将储存的数据存放在一个存储单元里面,并且这个存储单元里面还维护了下一个存储单元的地址。在LinkedList的链表储存单元中,不仅存放了下一个存储单元的地址,还存放了上一个单元的储存地址,因为Linked是双向链表,双向链表就是可以通过链表中任意一个存储单元可以获取...

weixin_30500365的博客 235

Sentinel-1 Burst数据处理避坑实录:从aria2c报错到wget脚本救场

本文详细介绍了Sentinel-1 Burst数据处理的完整解决方案,从下载困境到高效处理技巧。针对aria2c报错等常见问题,提供了增强版wget脚本和智能分组方法,显著提升下载成功率和处理效率,特别适合科研机构和企业级网络环境下的哨兵数据处理需求。

weixin_42641998的博客 284

JDK1.8中LinkedList的实现原理及源码分析

一、概述            LinkedList底层是基于双向链表(双向链表的特点,可以看下我的另外一篇博文:https://blog.csdn.net/cb_lcl/article/details/81217972),链表在内存中不是连续的,而是通过引用来关联所有的元素,所以链表的优点在于添加和删除元素比较快,因为只是移动指针,并且不需要判断是否需要扩容,缺点是查询和遍历效率比较低。 二...

cb_lcl的博客 1302

基于STM32的Modbus TCP多主站数据监测

Modbus TCP通信协议在STM32上实现,STM32作为服务器采集内部传感器数据,并通过ADC进行转换,存入寄存器。两个PC机作为客户端访问服务器,服务器通过Socket通信实现监听连接,将数据发送给客户端。

hyp12347的博客 4294

如何懂固高卡以及滚筒轴+平移轴配合运动?

🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!!

**My Coding Family** 847

java1.8 LinkedList的结构原理

public class Test { //链表,先进先出。双向链表结构,项目中可也会用到,其他方法自行研究。也可引申出红黑树,敬请关注我的博客 public static void main(String[] args) { MyLinkedList linkedList = new MyLinkedList(); linkedList.add("a1"...

半生@浮名的博客 332

ESP32-C3模组上实现蓝牙BLE配网功能(1)

ESP32-C3模组上实现蓝牙BLE配网功能(1)

phmatthaus的专栏 2279

类成员变量初始化列表(Member Initialization List)

1) 类成员初始化列表的顺序是很重要的#include using namespace std; class MemberInitializationList{private:         int i;         int j;public:         MemberInitializationList(int val) : j(val), i(

玄机逸士的专栏 3794

《Python入门到精通》函数详解

函数就是一段「封装」起来的「代码」,目的是提高代码的「模块性」和「复用性」。 2、函数的参数 2.1、变量的就近原则 2.2、传递参数 2.3、形参和实参 2.4、位置参数 2.5、缺省参数 2.6、可变类型和不可变类型 2.7、关键字参数 3、匿名函数 4、函数的返回值

wangyuxiang946的博客 1万+

HBase学习二:RegionServer详解

RegionServer是HBase系统中最核心的组件,主要负责用户数据写入、读取等基础操作。RegionServer组件实际上是一个综合体系,包含多个各司其职的核心模块:HLog、MemStore、HFile以及BlockCache。一个RegionServer由一个(或多个)HLog、一个BlockCache以及多个Region组成。其中,HLog用来保证数据写入的可靠性;BlockCache可以将数据块缓存在内存中以提升数据读取性能;

qwerty1372431588的博客 747

jdk1.6 1.7 1.8 LinkedList源码实现原理及区别

LinkedList(jdk1.6) private transient Entry&lt;E&gt; header = new Entry&lt;E&gt;(null, null, null); 定义一个空的Entry对象作为头结点,Entry是其内部定义的一个内部静态类,结构如下: private static class Entry&lt;E&gt; { E element...

JavaSheng的专栏 1685

CMCC-IPC-A410串口刷机救砖教程

《CMCC-IPC-A410摄像头串口刷机指南》摘要 本指南针对2018年前老款CMCC-IPC-A410摄像头变砖/升级失败的情况,提供串口刷机方案。需准备CH340G串口模块、杜邦线、海康V5.5.82固件等工具。操作包含硬件连接(TX/RX交叉接线)、115200波特率终端配置、CTRL+U进入刷机模式,通过UPF格式化、tftp传输固件、update写入等步骤完成修复。刷机后设备恢复未激活状态,需重置密码,原定制功能可能失效。整个过程需稳定供电,耗时约15-20分钟,注意此操作将使原厂保修失效。(1

海康威视技术支持 1845

Java集合源码剖析——基于JDK1.8中LinkedList的实现原理

Java集合源码剖析——基于JDK1.8中LinkedList的实现原理

贝尔摩德苦艾酒 8203

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

LinkedList源码之内部实现原理(jdk1.8)

LinkedList增删节点效率高,原因是内部基于链表实现,增删节点只需重新设置当前增删节点的左右节点指针即可 LinkedList的结构图: LinkedList的内部结构 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { //链表的节点个

泉眼和溪流的关系,大概是泉眼会被溪流一点一滴的占据 261

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

JDK1.8 LinkedList原理

目录 介绍 实现原理 优缺点 类图

zhujm320的专栏 346

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

基于jdk1.8的LinkedList的源码分析

基于jdk1.8的LinkedList的源码分析 LinkedList的特点 排列有序可重复 底层使用双向链表数据结构 查询速度慢,增删快 线程不安全 理解LinkedList主要需要理解几个概念: 首节点:只要指导首节点就可以根据首节点的下一个节点依此查找到其他节点。 尾节点:通过尾节点的上一个节点就可以依次查找到其他节点。 节点:节点包含上一个节点、节点元素、下一个节点;每一个节点需要保存上一个节点和下一个节点。对LinkedList的操作都是改变节点中上一个节点和下一个节点的指向。 Linke.

weixin_37442016的博客 220

使用循环链表实现一个通讯录的管理程序_LinkedList实现原理(JDK1.8)

精品推荐国内稀缺优秀Java全栈课程-Vue+SpringBoot通讯录系统全新发布!Docker快速手上视频教程(无废话版)【免费】作者:杨小格子转载自:https://www.cnblogs.com/imyanger/p/11980409.htmlLinkedList底层采用双向链表,如果对链表这种结构比较熟悉的话,那LinkedList的实现原理看明白就相当容易。链表通过“指针”将...

weixin_40001245的博客 297

JDK1.8源码学习-LinkedList

  JDK1.8源码学习-LinkedList 目录 一、LinkedList简介 LinkedList是一个继承于AbstractSequentialList的双向链表,是可以在任意位置进行插入和移除操作的有序序列。 LinkedList基于链表实现,在存储元素的过程中,无需像ArrayList那样进行扩容,但是有得必有失,LinkedList存储元素的节点需要额外的空间存储前...

bange7292的博客 245

jdk1.8 LinkedList

JDK1.8 LinkedList源码 构造方法 空参就是创建一个空的链表,可以将一个集合作为参数传进来,此时会新建一个空链表,然后把集合中的元素都拷贝过来 add()方法 第二句new Node()就表示创建一个新节点,节点元素为e,前继节点为l,后继节点为null add()方法的返回值为布尔类型,只会返回true; 添加的过程就是调用linkLast方法的过程,其中它会先将最后一个...

fanfan999的博客 1337

java集合

HashMap中,如果key经过hash算法得出的数组索引位置全部不相同,即Hash算法非常好,那样的话,getKey方法的时间复杂度就是O(1),如果Hash算法技术的结果碰撞非常多,假如Hash算极其差,所有的Hash算法结果得出的索引位置一样,那样所有的键值对都集中到一个桶中,或者在一个链表中,或者在一个红黑树中,时间复杂度分别为O(n)和O(lgn)。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。

weixin_72525373的博客 1012

JDK1.8-LinkedList源码分析

LinkedList源码解析

qq_40205337的博客 223

LinkedList简单的源码介绍(JDK1.8.0_211)

LinkedList源码浅析(JDK1.8.0_211) 序言:上一篇文章我们介绍了ArrayList源码,讲解了ArrayList是怎么实现增删改查的,现在我们就带大家走进另一个list LinkedList 1.LinkedList类 他跟ArrayList不同,LinkedList继承自AbstractSequentialList,实现了四个接口,我们重点看一下Deque Deque继承自...

zhuhewie的博客 321

JDK1.8源码之LinkedList

LinkedList采用双链表的数据结构,可以用作列表做存储,也可以用做双端队列。 部分属性与Node结构 //指向列表的第一个元素 transient Node<E> first; //指向列表的最后一个元素 transient Node<E> last; //Node节点 private static class Node<E&gt...

weixin_44181697的博客 237

LinkedList源码分析--jdk1.8

JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8ReentrantLock源码分析--jdk1.8 LinkedList概述   1.LinkedList是用双向链表实现的集合,基于内部类Node<E>实现的集合。  2.LinkedList支持双向链表访问、克隆、...

178
上一篇: ArrayList实现原理(JDK1.8)
杨小格
博客等级 码龄10年 19粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值