您的位置:首页 > 编程语言 > Java开发

深入学习java集合:LinkedList<E>实现

2016-05-27 21:25 621 查看
1、LinkedList类图



          LinkedList是 List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。所有操作都是按照双重链接列表的需要执行的。在列表中遍历索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。

         注意,此实现不是同步(线程安全)的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法来“包装”该列表。最好在创建时完成这一操作,以防止对列表进行意外的不同步访问,如下所示:
                    List list = Collections.synchronizedList(new LinkedList(...));


      此类的 iterator 和 listIterator 方法返回的迭代器是快速失败 的:在迭代器创建之后,如果从结构上对列表进行修改,除非通过迭代器自身的remove 或 add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来不确定的时间任意发生不确定行为的风险。

          注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何硬性保证。快速失败迭代器尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。

2、LinkedList构造实现以及重要方法

         对LinkdeList而言,底层实现是通过一个无头结点的双向链表,其所有操作都遵循双向链表。其基本结构为:

        


    主要的操作方法有 void linkFirst(E e),void linkLast(E e), void linkBefore(E e, Node<E> succ) ,E unlinkFirst(Node<E>
f), E unlinkLast(Node<E> l)。这些方法实现了链表的基本操作,可以看到他们都是私有的,其他的方法通过这几个基本方法实现。下面来分析LinkedList源码:

   1)构造器

 

   public LinkedList() {

    }

 public LinkedList(Collection<? extends E> c) {

        this();

        addAll(c);

    }

2)链表节点 Node 

       每个节点中记录数据项item,以及前一个节点prev和后一个节点next。

      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;

        }

    }

 3)linkFirst(e: E): void  从表头添加元素方法

         private void linkFirst(E e) {

        final Node<E> f = first;

        final Node<E> newNode = new Node<>(null, e, f);  //构造新节点,保存元素e

        first = newNode;

        if (f == null)  //如果是空链表,那么设置last  指向新节点

            last = newNode;

        else

            f.prev = newNode;  

        size++;

        modCount++;

    }

4) linkLast(e: E): void 在链表尾部添加元素方法

 void linkLast(E e) {

        final Node<E> l = last;

        final Node<E> newNode = new Node<>(l, e, null); //构造新节点,保存元素e

        last = newNode;

        if (l == null)  //如果是空链表,那么设置first 指向新节点

            first = newNode;

        else

            l.next = newNode;

        size++;

        modCount++;

    }

5) linkBefore(e: E, succ: Node<E>): void  在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);  //构造新节点,保存元素e

        succ.prev = newNode; //将新节点插入到succ前面

        if (pred == null)

            first = newNode;

        else

            pred.next = newNode;

        size++;

        modCount++;

    }

6) unlinkFirst(f: Node<E>): E    将头结点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 

            last = null;

        else

            next.prev = null;

        size--;

        modCount++;

        return element;

    }

7) unlinkLast(l: Node<E>): E   删除尾节点方法

    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;

    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息