类关系图

LinkedList - 图1

功能介绍

包路径java.util

功能描述: LinkedList 继承了AbstractSequentialList抽象类,同时实现了List的接口,允许有null(空)元素。主要用于创建双向链表数据结构**,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List

LinkedList - 图2

LinkedList最主要的功能方面的增强是可以在List的头部和尾部添加、删除、获取元素,直接提供了这些方法的实现。可以非常方便的实现数据结构中常见的Stack(栈)和Queue(队列)

链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。

特点非线程安全,查询慢,增删快(链表特性)

LinkedList 继承了 AbstractSequentialList 类,实现链式访问。
LinkedList 实现了 Deque 接口,可作为队列使用。

源码解析

AbstractSequentialList

AbstractSequentialList 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问。

  1. /**
  2. * @author Josh Bloch
  3. * @author Neal Gafter
  4. * @see Collection
  5. * @see List
  6. * @see AbstractList
  7. * @see AbstractCollection
  8. * @since 1.2
  9. */
  10. public abstract class AbstractSequentialList<E> extends AbstractList<E> {
  11. /**
  12. * Sole constructor. (For invocation by subclass constructors, typically
  13. * implicit.)
  14. */
  15. protected AbstractSequentialList() {
  16. }
  17. /**
  18. * 获取指定位置的元素
  19. */
  20. public E get(int index) {
  21. try {
  22. // 直接获取以index为初始位置的ListIterator
  23. return listIterator(index).next();
  24. } catch (NoSuchElementException exc) {
  25. throw new IndexOutOfBoundsException("Index: "+index);
  26. }
  27. }
  28. /**
  29. * 设置指定位置元素
  30. */
  31. public E set(int index, E element) {
  32. try {
  33. ListIterator<E> e = listIterator(index);
  34. E oldVal = e.next();
  35. e.set(element);
  36. return oldVal;
  37. } catch (NoSuchElementException exc) {
  38. throw new IndexOutOfBoundsException("Index: "+index);
  39. }
  40. }
  41. /**
  42. * 在指定位置插入元素
  43. */
  44. public void add(int index, E element) {
  45. try {
  46. listIterator(index).add(element);
  47. } catch (NoSuchElementException exc) {
  48. throw new IndexOutOfBoundsException("Index: "+index);
  49. }
  50. }
  51. /**
  52. * 移除指定位置的元素
  53. */
  54. public E remove(int index) {
  55. try {
  56. ListIterator<E> e = listIterator(index);
  57. E outCast = e.next();
  58. e.remove();
  59. return outCast;
  60. } catch (NoSuchElementException exc) {
  61. throw new IndexOutOfBoundsException("Index: "+index);
  62. }
  63. }
  64. // Bulk Operations
  65. /**
  66. * 往指定位置插入集合所有元素
  67. */
  68. public boolean addAll(int index, Collection<? extends E> c) {
  69. try {
  70. boolean modified = false;
  71. ListIterator<E> e1 = listIterator(index);
  72. Iterator<? extends E> e2 = c.iterator();
  73. while (e2.hasNext()) {
  74. e1.add(e2.next());
  75. modified = true;
  76. }
  77. return modified;
  78. } catch (NoSuchElementException exc) {
  79. throw new IndexOutOfBoundsException("Index: "+index);
  80. }
  81. }
  82. // Iterators
  83. /**
  84. *
  85. * @return an iterator over the elements in this list (in proper sequence)
  86. */
  87. public Iterator<E> iterator() {
  88. return listIterator();
  89. }
  90. /**
  91. * 返回ListIterator迭代器,未实现
  92. * @param index index of first element to be returned from the list
  93. * iterator (by a call to the <code>next</code> method)
  94. * @return a list iterator over the elements in this list (in proper
  95. * sequence)
  96. */
  97. public abstract ListIterator<E> listIterator(int index);
  98. }

Deque

LinkedList 实现了 Deque 接口,可作为队列使用。默认提供了头尾部插入和查找的方法

public interface Deque<E> extends Queue<E> {
    /**
     * 在头部插入元素
     * @param e the element to add
     */
    void addFirst(E e);

    /**
     * 在尾部追加元素
     * @param e the element to add
     */
    void addLast(E e);

    /**
     * 在头部插入元素,成功则返回true,否则返回false
     * 和addFirst方法的区别在于不是通过引发异常来停止插入的,如容量限制原因,下同
     * @param e the element to add
     * @return {@code true} if the element was added to this deque, else
     *         {@code false}
     */
    boolean offerFirst(E e);

    /**
     * 在尾部追加元素,成功则返回true,否则返回false
     * @param e the element to add
     * @return {@code true} if the element was added to this deque, else
     *         {@code false}
     */
    boolean offerLast(E e);

    /**
     * 移除首元素
     * @return the head of this deque
     * @throws NoSuchElementException if this deque is empty
     */
    E removeFirst();

    /**
     * 移除末尾元素
     * @return the tail of this deque
     * @throws NoSuchElementException if this deque is empty
     */
    E removeLast();

    /**
     * 检索并删除此双端队列的第一个元素,如果此双端队列为空,则返回null
     * @return the head of this deque, or {@code null} if this deque is empty
     */
    E pollFirst();

    /**
     * 检索并删除此双端队列的最后一个元素,如果此双端队列为空,则返回null
     * @return the tail of this deque, or {@code null} if this deque is empty
     */
    E pollLast();

    /**
     * 获取首元素
     * @return the head of this deque
     */
    E getFirst();

    /**
     * 获取尾元素
     * @return the tail of this deque
     */
    E getLast();

    /**
     * 检索但不删除此双端队列的第一个元素,如果此双端队列为空,则返回null
     * @return the head of this deque, or {@code null} if this deque is empty
     */
    E peekFirst();

    /**
     * 检索但不删除此双端队列的最后一个元素,如果此双端队列为空,则返回null。
     * @return the tail of this deque, or {@code null} if this deque is empty
     */
    E peekLast();

    /**
     * 删除队列中第一次出现的指定元素,如果双端队列不包含元素,则它保持不变
     * @param o element to be removed from this deque, if present
     * @return {@code true} if an element was removed as a result of this call
     */
    boolean removeFirstOccurrence(Object o);

    /**
     * 从此双端队列移除最后一次出现的指定元素。如果双端队列不包含元素,则它保持不变。
     * @param o element to be removed from this deque, if present
     * @return {@code true} if an element was removed as a result of this call
     */
    boolean removeLastOccurrence(Object o);

    // *** Queue methods ***

    /**
     * 添加元素到队列末尾,此方法等效于addLast(E),通常最好使用offer。
     * @param e the element to add
     * @return {@code true} (as specified by {@link Collection#add})
     */
    boolean add(E e);

    /**
     * 指定的元素插入此双端队列末尾,此方法等效于offerLast(E)
     * @param e the element to add
     * @return {@code true} if the element was added to this deque, else
     *         {@code false}
     */
    boolean offer(E e);

    /**
     * 检索并删除此双端队列代表的队列的首元素
     * @return the head of the queue represented by this deque
     * @throws NoSuchElementException if this deque is empty
     */
    E remove();

    /**
     * 检索并删除此双端队列表示的队列的首元素
     * @return the first element of this deque, or {@code null} if
     *         this deque is empty
     */
    E poll();

    /**
     * 检索但不删除此双端队列代表的队列的首元素,此方法等效于getFirst()。
     * @return the head of the queue represented by this deque
     */
    E element();

    /**
     * 检索但不删除此双端队列表示的队列的首元素,此方法等效于peekFirst()。
     * @return the head of the queue represented by this deque, or
     *         {@code null} if this deque is empty
     */
    E peek();


    // *** Stack methods ***

    /**
     * 将一个元素压入此双端队列表示的头部,此方法等效于addFirst(E)。
     * @param e the element to push
     */
    void push(E e);

    /**
     * 删除并返回此双端队列的第一个元素,此方法等效于removeFirst()。
     * @return the element at the front of this deque (which is the top
     *         of the stack represented by this deque)
     */
    E pop();


    // *** Collection methods ***

    /**
     * 移除第一次出现的指定元素,此方法等效于removeFirstOccurrence(java.lang.Object)
     * @param o element to be removed from this deque, if present
     * @return {@code true} if an element was removed as a result of this call
     */
    boolean remove(Object o);

    /**
     * 如果此双端队列包含指定的元素,则返回true
     * @param o element whose presence in this deque is to be tested
     * @return {@code true} if this deque contains the specified element
     */
    boolean contains(Object o);

    /**
     * 返回此双端队列的元素数量。
     * @return the number of elements in this deque
     */
    public int size();

    /**
     * 以适当的顺序返回此双端队列中的元素的迭代器。元素将按照从头(头)到后(尾)的顺序返回。
     * @return an iterator over the elements in this deque in proper sequence
     */
    Iterator<E> iterator();

    /**
     * 以相反的顺序返回此双端队列中的元素的迭代器。元素将按从最后(尾)到第一个(头)的顺序返回。
     * @return an iterator over the elements in this deque in reverse
     * sequence
     */
    Iterator<E> descendingIterator();

}

可以看到,Deque继承了Queue接口,作为队列的代表,提供了大量关于首位元素和末尾元素的直接操作方法。

LinkedList

主要属性

// 用来记录元素个数
transient int size = 0;

// 记录链表/队列头节点
transient Node<E> first;

// 记录链表/队列尾节点
transient Node<E> last;

构造方法

public LinkedList() {
}

/**
 * 构建LinkedList同时添加集合元素
 */
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

核心子类—Node

Node子类代表了LinkedList的一个元素封装

private static class Node<E> {

    // 元素本身
    E item;

    // 前一个结点
    Node<E> prev;

    // 后一节点
    Node<E> next;

    /**
     * 构造函数,构建一个节点,指定其前一节点以及后一节点
     */
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

**

核心方法

(1) 连接与解除连接

只有节点里面的item为空值,不可能存在空节点,当链表中first节点为null,代表链表没有任何节点

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    /**
     * 将传入元素连接到链表首元素前面,也就是成为首元素
     * Links e as first element.
     */
    private void linkFirst(E e) {
        final Node<E> f = first;

        // null <- e -> f
        final Node<E> newNode = new Node<>(null, e, f);

        // 传入元素作为首节点
        first = newNode;

        // 如果原本首节点就是空的,则现在链表只有一个元素
        if (f == null)
            last = newNode; // 尾元素就是首元素
        else
            f.prev = newNode; // 否则f关联前一个元素:e <-> f

        // 元素数量+1
        size++;

        // 修改次数+1
        modCount++;
    }

    /**
     * 插入到last节点的后面
     * Links e as last element.
     */
    void linkLast(E e) {
        final Node<E> l = last;

        // l <- e -> null
        final Node<E> newNode = new Node<>(l, e, null);

        // 新插入的节点成为尾节点
        last = newNode;

        // 如果原本last就是空的,证明之前没有元素,现在只有一个元素
        if (l == null)
            first = newNode; // 首节点即尾节点
        else
            l.next = newNode; // l <-> e

        // 元素数量+1
        size++;

        // 修改次数+1
        modCount++;
    }

    /**
     * 将e插入到succ节点之前
     * Inserts element e before non-null Node succ.
     */
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;

        // 获取succ节点的前一节点
        final Node<E> pred = succ.prev;

        // 构造节点:pred <- e -> succ
        final Node<E> newNode = new Node<>(pred, e, succ);

        // e <-> succ
        succ.prev = newNode;

        // 如果pred为null节点,证明succ之前为首节点
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode; // pred <-> e

        // 元素数量+1
        size++;

        // 修改次数+1
        modCount++;
    }

    /**
     * 解除首位元素关联,也就是删除首元素
     * Unlinks non-null first node f.
     */
    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;

        // 获取首节点内容
        final E element = f.item;

        // 获取首节点下一节点
        final Node<E> next = f.next;

        // f节点置空,以便回收空间
        f.item = null;
        f.next = null; // help GC

        // 下一节点转为首节点
        first = next;

        // 如果下一节点本就为null,证明原本就只有一个节点
        if (next == null)
            last = null;
        else
            next.prev = null;

        // 元素数量-1
        size--;

        // 修改次数+1
        modCount++;

        return element;
    }

    /**
     * 解除末尾元素关联,也就是删除尾元素
     * Unlinks non-null last node 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

        // prev成为尾节点
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
    }

    /**
     * 删除指定节点
     * Unlinks non-null 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;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }
}

(2) add方法—添加元素
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

    /**
     * 将元素追加到链表结尾
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    /**
     * 向指定位置插入元素
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     */
    public void add(int index, E element) {

        // 检查位置是否合法,index不可以<0 也不可以>size
        checkPositionIndex(index);

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

    /**
     * 将元素添加到首节点前
     * @param e the element to add
     */
    public void addFirst(E e) {
        linkFirst(e);
    }

    /**
     * 将元素添加到末尾
     *
     * @param e the element to add
     */
    public void addLast(E e) {
        linkLast(e);
    }

    /**
     * 添加传入集合全部元素
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     */
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    /**
     * 在指定位置插入集合全部元素
     * @param index index at which to insert the first element
     *              from the specified collection
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     */
    public boolean addAll(int index, Collection<? extends E> c) {

        // 检查位置是否合法,index不可以<0 也不可以>size
        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);

            // 如果前一节点为null,表明index位置为首元素位置
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;

            pred = newNode;
        }


        // 如果原位置节点为null,则表明原先链表为空
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }
        size += numNew;
        modCount++;
        return true;
    }

}

(3) remove方法—-删除元素
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

    /**
     * 移除指定位置元素
     * @param index the index of the element to be removed
     * @return the element previously at the specified position
     */
    public E remove(int index) {

        // 检查位置是否合法
        checkElementIndex(index);

        // 解除元素关联,即移除
        return unlink(node(index));
    }

    /**
     * 移除最先出现的指定元素,如果存在且移除成功则返回true
     * @param o element to be removed from this list, if present
     * @return {@code true} if this list contained the specified element
     */
    public boolean remove(Object o) {

        // 如果传入元素为null,则匹配item为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;
    }

    /**
     * 移除首节点
     * @return the first element from this list
     * @throws NoSuchElementException if this list is empty
     */
    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

    /**
     * 移除末尾节点
     * @return the last element from this list
     * @throws NoSuchElementException if this list is empty
     */
    public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }

    /**
     * 移除第一个出现的指定元素
     * @param o element to be removed from this list, if present
     * @return {@code true} if the list contained the specified element
     */
    public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }

    /**
     * 移除最后一个出现的指定元素
     * @param o element to be removed from this list, if present
     * @return {@code true} if the list contained the specified element
     * @since 1.6
     */
    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;
    }

}

(4) set/get方法-设置与获取
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    /**
     * 设置指定位置元素
     * @param index index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     */
    public E set(int index, E element) {

        // 检查位置合法性
        checkElementIndex(index);

        // 获取指定位置节点
        Node<E> x = node(index);

        // 获取旧值
        E oldVal = x.item;

        // 设定新值
        x.item = element;

        // 返回旧值
        return oldVal;
    }

    /**
     * 获取指定位置元素
     * @param index index of the element to return
     * @return the element at the specified position in this list
     */
    public E get(int index) {

        // 检查位置合法性 
        checkElementIndex(index);

        // 返回节点值
        return node(index).item;
    }

    /**
     * 获取首节点值
     * @return the first element in this list
     */
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

    /**
     * 获取尾节点值
     * @return the last element in this list
     */
    public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }

    /**
     * 获取指定位置的节点对象
     */
    Node<E> node(int index) {
        // assert isElementIndex(index);

        // 如果index < size/2,也就是离开头更近
        if (index < (size >> 1)) {
            Node<E> x = first;

            // 从开头往后遍历
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;

        } else { // 如果index离结尾更近
            Node<E> x = last;

            // 从结尾往前遍历
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
}

我们可以看到,需要查找指定位置的元素(除了首尾元素),我们只能通过遍历链表的方式去获取,所以查询起来相对较慢。

简单使用

public class LinkedListCode {
    public static void main(String[] args) {
        commonExample();
    }

    public static void commonExample(){
        LinkedList<Integer> linkedList = new LinkedList<>();
        for(int i=0;i<10;i++){
            linkedList.add(i);
        }
        System.out.println("原始链表:"+linkedList);
        System.out.println("首元素:"+linkedList.getFirst());
        System.out.println("尾元素:"+linkedList.getLast());

        // 在首节点前插入元素
        linkedList.addFirst(-1);
        System.out.println("前插数据后:"+linkedList);

        // 在尾节点后追加元素
        linkedList.addLast(10);
        System.out.println("后加数据后:"+linkedList);
    }
}

输出:

原始链表:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
首元素:0
尾元素:9
前插数据后:[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
后加数据后:[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

总结

1、LinkedList 继承了AbstractSequentialList抽象类,同时实现了List的接口,允许有null(空)元素。主要用于创建双向链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List

2、LinkedList的特点是非线程安全,查询慢,增删快(链表特性)

3、LinkedList 继承了 AbstractSequentialList 类,实现链式访问。LinkedList还 实现了 Deque 接口,可作为队列使用。

4、LinkedList内部使用Node子类作为一个元素的封装

思考

什么时候用ArrayList,什么时候用LinkedList?

以下情况使用 ArrayList :

  • 频繁访问列表中的某一个元素。
  • 只需要在列表末尾进行添加和删除元素操作。

以下情况使用 LinkedList :

  • 你需要通过循环迭代来访问列表中的某些元素。
  • 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。

为什么说LinkedList是线程不安全的?

和ArrayList一样,我们在LinkedList的add、set、remove等非原子性操作上都没有看到任何关于并发锁的代码,这就已经表明了它是非线程安全的

如何解决这个线程安全问题:
1、使用线程安全的队列:ConcurrentLinkedQueue【内部使用CAS安全算法保证线程安全】
图片.png
2、使用Collections.synchronizedList(new LinkedList()),锁定区间的方式保证同步

3、使用Vector(内部主要使用synchronized关键字实现同步)