Java之LinkedList源码分析(第三篇:添加元素-List接口相关方法分析)

(注意:本文源码基于JDK1.8) 

LinkedList实现了List接口,截图为List接口中定义的添加元素的方法,实现List接口表示具备线性表的能力【此文未提及迭代器中的add()方法】

 

add(E)方法分析

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

用于添加1个元素的方法,传入参数为添加的元素对象

1、调用linkLast()方法

首先调用linkLast()方法,传入参数为要添加的元素对象

2、向调用者返回添加结果

默认返回值为true,表示添加元素成功

 

add(int,E)方法分析

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

用于在指定下标处添加元素的方法,传入的第一个参数index表示添加元素的位置,第二个参数表示添加的元素对象

1、检查下标值是否符合要求

调用checkPositionIndex()方法用于检查添加元素的位置,只有符合范围的下标才能正常添加,正常范围是指在现有范围内才能添加元素,比如现在LinkedList对象持有3个元素,

那么index的合法下标范围是0-2,不符合范围的index值,作者会抛出异常告诉调用者

2、检查元素位置,不同的情况采用不同的方法

当index值与size值相同,说明指定的下标正好需要添加到LinkedList的尾部,那么此时调用的是linkLast()方法

当在中间处添加元素时,则调用linkBefore()方法添加元素

 

addAll(Collection)方法分析

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

用于添加多个元素的方法,传入参数为持有多个元素的Collection对象

1、调用addAll()方法添加元素

2、向调用者返回添加元素的结果,其实是addAll()方法的结果

 

addAll(int,Collection)方法分析

    public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

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

用于向指定位置处添加多个元素,传入的第一个参数表示添加元素的起始位置处,传入的第二个参数表示持有多个元素的Collection对象

1、检查下标值是否符合要求

通过调用checkPostionIndex()方法检查下标是否符合要求,不符合要求作者会抛出异常

2、将传入的多个元素转化为数组对象

传入的Collection持有多个元素,先将这些元素转换为Object数组对象,并由局部变量a负责保存……

3、提取传入的元素数量

通过数组对象的属性length提取出元素总数,并由局部变量numNew负责保存

4、检查添加的元素总数

当添加的元素总数numNew为0时,整个方法返回false,表示添加元素失败

5、先创建两个Node类型的局部变量

6、检查即将添加元素的位置index,根据不同的位置采用不同的添加方法

在尾部添加元素:当index与size值相同,此时刚好在尾部添加元素,这时局部变量succ赋值为null,局部变量pred则负责保存即将添加元素的上一个元素

在中间添加元素:在需要在中间位置添加元素时,局部变量succ用于保存即将添加元素的下一个元素,而局部变量pred则仍然负责保存即将添加元素的上一个元素

7、遍历传入的所有元素

每次会传入的元素对象,强行转换为类型参数对应的对象

针对添加的元素为第一个时,为LinkedList对象持有的first指向第一个Node对象

添加的元素不是第一个时,则使用节点对象的next一个一个的将元素链接起来……

更新当前节点对象……链表的元素添加,真是好玩

8、更新即将插入的元素的下一个元素的情况,两种情况

在尾部添加元素:即将添加的元素本身是从最后一个元素开始添加的,此时succ为null,所以需要更新last指向最后一个节点对象

在中间添加元素:更新添加的最后一个元素指向最后一个节点,更新最后一个元素指向已添加元素的最后一个

9、更新元素数量

size + numNew,然后赋值给size

10、更新modCount值,+1,表示LinekdList中已发生改变

11、向调用者返回true,表示添加元素成功

 

linkLast()方法分析

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

向LinkedList的尾部添加元素的方法,LinkedList中向尾部添加元素,主要使用的是该方法,传入的参数为需要添加的元素对象,它的类型是类型参数E,由我们指定元素的类型参数

1、本地保存last指向的Node对象

LinkedList对象持有的实例变量last,指向的是双向链表中的最后一个节点对象(Node对象),此处将其引用保存到局部变量l中

2、创建Node对象,用于持有元素对象

通过new一个Node对象,Node对象需要传入3个参数,第一个参数为当前LinkedList中的最后一个Node对象,第二个参数表示即将要添加的元素对象,第三个参数表示当前Node对象指向的下一个元素,此处传入的是null,因为添加的Node对象都是在尾部的……

3、更新LinekdList持有的最后一个Node对象

为LinkedList对象持有的last,指向为新创建的Node对象

4、更新原尾部节点对象指向新的Node对象,对两种情况处理

首个元素:若添加的元素为第一个元素,此时局部变量l一定为null,因为LinkedList并没有持有任何元素,此时更新LinkedList对象持有的first指向新添加的Node对象

非首个元素:将原尾部的最后一个Node对象持有的下一个元素引用next指向新添加的元素对象

5、更新元素总数

size增加1

6、更新modCount值,表示LinkedList的元素发生改变,防止多线程下使用LinkedList,这是fail-fast机制的要求

 

linkBefore()方法分析

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

用于向某个元素的前面插入一个元素的方法,传入的参数e表示即将要插入的元素,传入的参数succ表示,即将插入的元素的下一个元素……,即某个元素……

1、先提取某个元素的上一个元素,保存在局部变量pred中

2、创建Node对象,用于持有即将添加的元素对象

创建Node对象,需传入3个参数,第一个参数表示当前Node对象指向的上一个Node对象,第二个参数表示元素对象,第三个参数表示当前Node对象指向的下一个Node对象,新创建的Node保存在局部变量newNode中

3、更新succ的指向新插入的Node对象

4、更新新插入Node对象的上一个Node对象的指向,这里是两种情况

新添加的是第一个Node对象:此时更新first指向Node对象

新添加的为中间的Node对象:此时更新上一个Node对象指向新创建的Node对象

5、更新元素总数

size+1

6、modCount增加1,表示LinkedList的元素发生改变

 

checkPositionIndex()方法分析

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

用于检查插入元素的位置是否合理的方法,传入的参数index表示需要插入的位置,比如第一个元素的位置是0

1、调用isPositionIndex()方法判断index是否合理

2、当判断不合理时,先生成异常文本信息

由outOfBoundsMsg()方法生成文本字符串

3、创建IndexOutOfBoundsException对象,并向用户抛出……

 

isPositionIndex()方法分析

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

用于判断位置是否合理的方法,传入的参数index表示添加元素的位置

当传入的位置index大于等于0并且小于等于size值时,才是符合要求的位置

 

总结

1、LinkedList作为双向链表,使用Node对象持有每个元素对象,本片未详细提及Node对象,后面的文章会分析

2、向尾部添加元素、向中间添加元素,注意引用的变化

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值