JDK源码阅读——LinkedList

只写一些比较常用的方法

首先要明确一个基础知识,LinkedList是链表结构,是通过地址相连的,举个栗子: 链表中有A B C三个元素 他们每一个都有一个相应的节点对象 节点对象有 prev 和 next两个属性 A元素的 prev中存储的为null 因为是第一个元素 next中存储的是B 元素的节点对象 这样这两个元素就连接在一起了,同理可证,B元素中的 prev含有 A元素的节点对象 next含有C元素的节点对象等等 以此类推。

获取第一个或者最后一个元素

//Node是节点对象,先判断节点对象是否为空,如果为空说明这个链表就是空的,因为没有第一个元素。如果不为空就返回 item , item是节点对象的一个属性,存储着元素的值
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 E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
            //调用unlinkFirst方法 下面我们一起看一下这个方法
        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
        //将第二个元素的节点对象赋值给firest 直接断开与第一个对象的连接(firest为LinkedList的一个属性,代表第一个元素)
        first = next;
        //如果等于NULL说明集合已经为空
        if (next == null)
            last = null;
        else
        //如果不为空就将第二个元素与第一个元素的连接断开
            next.prev = null;
            //长度减一
        size--;
        modCount++;
        return element;
    }
//删除最后一个元素 与上面的原理相同

将元素添加到开头或者结尾

//主要调用linkFirst 方法 下面我们一起看一下
public void addFirst(E e) {
        linkFirst(e);
    }

private void linkFirst(E e) {
//先获取第一个元素节点对象
        final Node<E> f = first;
        //为当前对象创建节点对象 参数为 1. prev 与上一个节点对象的连接(因为是第一个所以为Null) 
        //2 参数本身,会成为节点对象的一个属性 3.next 与下个节点连接的节点对象(将原来第一个的元素变成第二个,所以参数为f)
        final Node<E> newNode = new Node<>(null, e, f);
        //将新节点赋值到firest
        first = newNode;
        //判断f是否为空,如果为空说明集合就只有一个元素
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }
//添加到末尾的原理与上面的相同

集合中是否包含某元素

//这个方法调用的是indexOf 方法 下面我们一起看一下
public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

//查找目标对象索引
    public int indexOf(Object o) {
        int index = 0;
        //判断查找对象是否为null
        if (o == null) {
            //先拿到第一个节点对象,然后依次循环,直到找到目标对象
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            //与上面的循环同理
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        //找不到返回-1
        return -1;
    }

删除元素


public boolean remove(Object o) {
        if (o == null) {
        //循环,先创建一个节点对象,并赋值为第一节点。结束循环的条件为 节点对象为Null 一次循环后就获取下一个节点继续循环
            for (Node<E> x = first; x != null; x = x.next) {
            //判断是否找到了目标对象
                if (x.item == null) {
                //找到了就调用unlink 方法删除
                    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;
    }
//上面调用的unlink 方法
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为null说明是第一个元素
        if (prev == null) {
            //直接将下一个节点对象赋值给first 这样链表和要删除的节点就断开连接了
            first = next;
        } else {
            //将前一个节点的指针直接指向要删除元素的下一个节点对象
            prev.next = next;
            //删除X的前节点对象
            x.prev = null;
        }

        //与上面同理
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        //清空数据
        x.item = null;
        size--;
        modCount++;
        return element;
    }

将一个集合中的元素添加到链表中

//调用addAll方法 下面一起看一下
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;

        //Node<E>是一个节点对象,主要是存储跟他相连上一个和下一个节点的索引信息的(链表)
        Node<E> pred, succ;
        //如果添加位置在链表最后 则让pred等于原链表的最后一个元素的节点对象
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            //如果不是在最后,就获取index索引位置和其前面的节点对象
            succ = node(index);
            pred = succ.prev;
        }

        //循环主要是进行元素的插入操作,体现在pred的变化上。循环开始前 pred是目标index的前一个元素的节点对象。
        //循环结束后pred是要插入集合的最后一个元素的节点对象
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            //为当前对象创建节点对象
            Node<E> newNode = new Node<>(pred, e, null);
            //先判断pred 节点对象是否为空,如果为空证明是第一个元素
            if (pred == null)
                first = newNode;
            else
                //如果不为空就将上一个节点对象(也就是index位置的上一个元素)的指针只向待插入对象
                pred.next = newNode;
            //将待插入对象的节点对象赋值给pred。这一步就完成了pred的转换。
            //由index的上一个元素的节点对象变成了index对象,并作为下一次循环中新节点对象的前一个对象。
            pred = newNode;
        }

        //如果满足条件说明是最后一个对象,就将pred赋值给最后一个节点对象
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

清空集合


 //清空集合
    public void clear() {
        // Clearing all of the links between nodes is "unnecessary", but:
        // - helps a generational GC if the discarded nodes inhabit
        //   more than one generation
        // - is sure to free memory even if there is a reachable Iterator
        //创建节点对象X 并赋值为第一个节点对象,直到X 等于null说明已经到最后一个对象了
        for (Node<E> x = first; x != null; ) {
            //先取出该节点的下一个节点对象,并将所有属性赋值为null
            Node<E> next = x.next;
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }

在指定位置添加元素


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

        //如果将元素添加到最后
        if (index == size)
            linkLast(element);
        else
            //如果不是就调用linkBefore方法
            linkBefore(element, node(index));
    }

//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++;
    }
//add方法调用
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节点对象的指针指向newNode对象
        succ.prev = newNode;
        //主要是判断集合是否为空
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

获取链表第一个元素


public E peek() {
        //获取第一个元素的数据
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
    
public E element() {
        //返回第一个元素,与上面的不同是 这个方法不能返回Null
        return getFirst();
    }
    //比较简单就不介绍了
public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

获取迭代器


//获得迭代器
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }

集合转数组


//跟ArrayList一样,也是将集合转成数组 这个方法只能返回Object类型的数组
    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;
    }

//跟ArrayList一样,也是将集合转成数组 这个方法可以返回指定泛型
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            a = (T[])java.lang.reflect.Array.newInstance(
                                a.getClass().getComponentType(), size);
        int i = 0;
        Object[] result = a;
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;

        if (a.length > size)
            a[size] = null;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值