Java集合之LinkedList源码分析

一、LinkedList简介

  LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表实现的。

  ps:这里有一个问题,就是关于实现LinkedList的数据结构是否为循环的双向链表,上网搜了有很多文章都说是循环的,并且有的文章中但是我看了源代码觉得应该不是循环的?

  例如在删除列表尾部节点的代码:

  private E unlinkLast(Node<E> l) 
{
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; }

  这里删除尾节点l后,将l前面的节点prev的next置为null,而并没有指向head节点。不知道是不是因为代码版本的原因(我的源代码是在下载的jdk1.8.0_45文件中获取的),如果读者看到知道原因,希望能够帮忙解答!

  在源码中定义了节点的基本结构:

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

  LinkedList的类图如下所示:

《Java集合之LinkedList源码分析》

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。

二、LinkedList源码分析

  1 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  2 {
  3    //实现Serilizable接口时,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
  4     transient int size = 0;
  5     //指向首节点
  6     transient Node<E> first;
  7     //指向最后一个节点
  8     transient Node<E> last;
  9     //构建一个空列表
 10     public LinkedList() {
 11     }
 12     //构建一个包含集合c的列表
 13     public LinkedList(Collection<? extends E> c) {
 14         this();
 15         addAll(c);
 16     }
 17    //将节点值为e的节点作为首节点
 18     private void linkFirst(E e) {
 19         final Node<E> f = first;
 20         //构建一个prev值为null,next为f,节点值为e的节点
 21         final Node<E> newNode = new Node<>(null, e, f);
 22         //将newNode作为首节点
 23         first = newNode;
 24         //如果newNode后面没有节点就将newNode作为最后一个节点
 25         if (f == null)
 26             last = newNode;
 27         //否则就将newNode赋给其prev
 28         else
 29             f.prev = newNode;
 30         //列表长度加一
 31         size++;
 32         modCount++;
 33     }
 34     //将节点值为e的节点作为最后一个节点
 35     void linkLast(E e) {
 36         final Node<E> l = last;
 37       //构建一个prev值为l,next为null,节点值为e的节点
 38         final Node<E> newNode = new Node<>(l, e, null);
 39         last = newNode;
 40         if (l == null)
 41             first = newNode;
 42         else
 43             l.next = newNode;
 44         size++;
 45         modCount++;
 46     }
 47     //在非空节点succ之前插入节点e
 48     void linkBefore(E e, Node<E> succ) {
 49         final Node<E> pred = succ.prev;
 50         //将succ前面的节点和succ作为其prev和next
 51         final Node<E> newNode = new Node<>(pred, e, succ);
 52         //然后将newNode作为succ的prev
 53         succ.prev = newNode; 
 54         //如果原来succ是首节点,则将newNode设置为首节点
 55         if (pred == null)
 56             first = newNode;
 57         else
 58             pred.next = newNode;
 59         size++;
 60         modCount++;
 61     }
 62      //释放非空的首节点f
 63     private E unlinkFirst(Node<E> f) {
 64         final E element = f.item;
 65         final Node<E> next = f.next;
 66         f.item = null;
 67         f.next = null; // help GC
 68         //将first节点后面的节点设为首节点
 69         first = next;
 70         if (next == null)
 71             last = null;
 72         else
 73             next.prev = null;
 74         size--;
 75         modCount++;
 76         return element;
 77     }
 78      //释放非空的尾节点l
 79        private E unlinkLast(Node<E> l) {
 80         final E element = l.item;
 81         final Node<E> prev = l.prev;
 82         l.item = null;
 83         l.prev = null; // help GC
 84         last = prev;
 85         if (prev == null)
 86             first = null;
 87         else
 88             prev.next = null;
 89         size--;
 90         modCount++;
 91         return element;
 92     }
 93     //删除非空节点x
 94     E unlink(Node<E> x) 
 95     {
 96         final E element = x.item;
 97         final Node<E> next = x.next;    //x后面的节点
 98         final Node<E> prev = x.prev;    //x前面的节点
 99 
100         if (prev == null) {
101             first = next;
102         } else {
103             prev.next = next;
104             x.prev = null;
105         }
106         if (next == null) {
107             last = prev;
108         } else {
109             next.prev = prev;
110             x.next = null;
111         }
112         x.item = null;
113         size--;
114         modCount++;
115         return element;
116     }
117     //返回列表首节点元素值
118     public E getFirst() {
119         final Node<E> f = first;
120         if (f == null)
121             throw new NoSuchElementException();
122         return f.item;
123     }
124     //返列表尾节点元素值
125     public E getLast() {
126         final Node<E> l = last;
127         if (l == null)
128             throw new NoSuchElementException();
129         return l.item;
130     }
131     //移除首节点
132     public E removeFirst() {
133         final Node<E> f = first;
134         if (f == null)
135             throw new NoSuchElementException();
136         return unlinkFirst(f);
137     }
138    //删除尾节点
139     public E removeLast() {
140         final Node<E> l = last;
141         if (l == null)
142             throw new NoSuchElementException();
143         return unlinkLast(l);
144     }
145   //在列表首部插入节点e
146     public void addFirst(E e) {
147         linkFirst(e);
148     }
149     //在列表尾部插入节点e
150     public void addLast(E e) {
151         linkLast(e);
152     }
153    //判断列表中是否包含有元素o
154     public boolean contains(Object o) {
155         return indexOf(o) != -1;
156     }
157     //返回列表长度大小
158     public int size() {
159         return size;
160     }
161     //在列表尾部插入元素
162     public boolean add(E e) {
163         linkLast(e);
164         return true;
165     }
166     //删除元素为o的节点
167     public boolean remove(Object o) 
168     {    
169         if (o == null) {
170             for (Node<E> x = first; x != null; x = x.next) {
171                 if (x.item == null) {
172                     unlink(x);
173                     return true;
174                 }
175             }
176         } else {
177             for (Node<E> x = first; x != null; x = x.next) {
178                 if (o.equals(x.item)) {
179                     unlink(x);
180                     return true;
181                 }
182             }
183         }
184         return false;
185     }
186    //将集合c中所有元素添加到列表的尾部
187     public boolean addAll(Collection<? extends E> c) {
188         return addAll(size, c);
189     }
190    //从指定的位置index开始,将集合c中的元素插入到列表中
191     public boolean addAll(int index, Collection<? extends E> c) {
192         //首先判断插入位置的合法性
193         checkPositionIndex(index);
194         Object[] a = c.toArray();
195         int numNew = a.length;
196         if (numNew == 0)
197             return false;
198         Node<E> pred, succ;
199         if (index == size) {//说明在列表尾部插入集合元素
200             succ = null;
201             pred = last;
202         } 
203         else {  //否则,找到index所在的节点
204             succ = node(index);
205             pred = succ.prev;
206         }
207         for (Object o : a) {
208             @SuppressWarnings("unchecked") E e = (E) o;
209             Node<E> newNode = new Node<>(pred, e, null);
210             if (pred == null)
211                 first = newNode;
212             else
213                 pred.next = newNode;
214             pred = newNode;
215         }
216         if (succ == null) {
217             last = pred;
218         } else {
219             pred.next = succ;
220             succ.prev = pred;
221         }
222         size += numNew;
223         modCount++;
224         return true;
225     }
226     //删除列表中所有节点
227     public void clear() {
228         for (Node<E> x = first; x != null; )  
229         {
230             Node<E> next = x.next;
231             x.item = null;
232             x.next = null;
233             x.prev = null;
234             x = next;
235         }
236         first = last = null;
237         size = 0;
238         modCount++;
239     }
240     //获取指定索引位置节点的元素值
241     public E get(int index) {
242         checkElementIndex(index);
243         return node(index).item;
244     }
245     //替换指定索引位置节点的元素值
246     public E set(int index, E element) {
247         checkElementIndex(index);
248         Node<E> x = node(index);
249         E oldVal = x.item;
250         x.item = element;
251         return oldVal;
252     }
253     //在指定索引位置之前插入元素e
254     public void add(int index, E element) {
255         checkPositionIndex(index);   
256         if (index == size)
257             linkLast(element);
258         else
259             linkBefore(element, node(index));
260     }
261     //删除指定位置的元素
262     public E remove(int index) {
263         checkElementIndex(index);
264         return unlink(node(index));
265     }
266     //判断指定索引位置的元素是否存在
267     private boolean isElementIndex(int index) {
268         return index >= 0 && index < size;
269     }
270     private boolean isPositionIndex(int index) {
271         return index >= 0 && index <= size;
272     }
273     //构建 IndexOutOfBoundsException详细信息
274     private String outOfBoundsMsg(int index) {
275         return "Index: "+index+", Size: "+size;
276     }
277     private void checkElementIndex(int index) {
278         if (!isElementIndex(index))
279             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
280     }
281     private void checkPositionIndex(int index) {
282         if (!isPositionIndex(index))
283             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
284     }
285     //返回指定索引位置的节点
286     Node<E> node(int index) {
287         //此处是一个小技巧,当index<size/2时,从列表前半部分开始,否则从后半部分开始
288         if (index < (size >> 1)) {
289             Node<E> x = first;
290             for (int i = 0; i < index; i++)
291                 x = x.next;
292             return x;
293         } else {
294             Node<E> x = last;
295             for (int i = size - 1; i > index; i--)
296                 x = x.prev;
297             return x;
298         }
299     }//返回列表中第一次出现o的位置,若不存在则返回-1
300     public int indexOf(Object o) {
301         int index = 0;
302         if (o == null) {
303             for (Node<E> x = first; x != null; x = x.next) {
304                 if (x.item == null)
305                     return index;
306                 index++;
307             }
308         } else {
309             for (Node<E> x = first; x != null; x = x.next) {
310                 if (o.equals(x.item))
311                     return index;
312                 index++;
313             }
314         }
315         return -1;
316     }
317     //逆向搜索,返回第一出现o的位置,不存在则返回-1
318     public int lastIndexOf(Object o) {
319         int index = size;
320         if (o == null) {
321             for (Node<E> x = last; x != null; x = x.prev) {
322                 index--;
323                 if (x.item == null)
324                     return index;
325             }
326         } else {
327             for (Node<E> x = last; x != null; x = x.prev) {
328                 index--;
329                 if (o.equals(x.item))
330                     return index;
331             }
332         }
333         return -1;
334     }
335    //获取列表首节点元素值
336     public E peek() {
337         final Node<E> f = first;
338         return (f == null) ? null : f.item;
339     }
340 
341     //获取列表首节点元素值,若为空则抛异常
342     public E element() {
343         return getFirst();
344     }
345    //检索首节点,若空则返回null,不为空则返回其元素值并删除首节点
346     public E poll() {
347         final Node<E> f = first;
348         return (f == null) ? null : unlinkFirst(f);
349     }
350     //检索首节点,若空则抛异常,不为空则返回其元素值并删除首节点
351     public E remove() {
352         return removeFirst();
353     }
354    //在列表尾部增加节点e
355     public boolean offer(E e) {
356         return add(e);
357     }
358    //在列表首部插入节点e
359     public boolean offerFirst(E e) {
360         addFirst(e);
361         return true;
362     }
363   //在列表尾部插入节点e
364     public boolean offerLast(E e) {
365         addLast(e);
366         return true;
367     }
368     public E peekFirst() {
369         final Node<E> f = first;
370         return (f == null) ? null : f.item;
371      }
372   //获取列表尾节点元素值
373     public E peekLast() {
374         final Node<E> l = last;
375         return (l == null) ? null : l.item;
376     }
377     public E pollFirst() {
378         final Node<E> f = first;
379         return (f == null) ? null : unlinkFirst(f);
380     }
381     public E pollLast() {
382         final Node<E> l = last;
383         return (l == null) ? null : unlinkLast(l);
384     }
385    //入栈
386     public void push(E e)
387     {
388         addFirst(e);
389     }
390     //出栈
391     public E pop() {
392         return removeFirst();
393     }
394     //删除列表中第一出现o的节点
395     public boolean removeFirstOccurrence(Object o) {
396         return remove(o);
397     }
398     //逆向搜索,删除第一次出现o的节点
399     public boolean removeLastOccurrence(Object o) {
400         if (o == null) {
401             for (Node<E> x = last; x != null; x = x.prev) {
402                 if (x.item == null) {
403                     unlink(x);
404                     return true;
405                 }
406             }
407         } else {
408             for (Node<E> x = last; x != null; x = x.prev) {
409                 if (o.equals(x.item)) {
410                     unlink(x);
411                     return true;
412                 }
413             }
414         }
415         return false;
416     }

 

三、关于LinkedList的几点说明

  1、注意源码中的 Node<E> node(int index)方法:

    Node<E> node(int 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与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历。

  2、LinkedList与ArrayList的区别:

  LinkedList与ArrayList在性能上各有优缺点,都有各自适用的地方,总结如下:

  • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
  • LinkedList不支持高效的随机元素访问。
  • ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间,就存储密度来说,ArrayList是优于LinkedList的。  

  总之,当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

  3、LinkedList中允许元素为null

  在查找和删除时,源代码如下所示:

   public int indexOf(Object o) {
        int index = 0;
        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++;
            }
        }
        return -1;
    }

  4、利用LinkedList实现栈操作

public class Stack<T>
{
    private LinkedList<T> stack;
    
    //无参构造函数
    public Stack()
    {
        stack=new LinkedList<T>();
    }
    //构造一个包含指定collection中所有元素的栈
    public Stack(Collection<? extends T> c)
    {
        stack=new LinkedList<T>(c);
    }
    //入栈
    public void push(T t)
    {
        stack.addFirst(t);
    }
    //出栈
    public T pull()
    {
        return stack.remove();
    }
    //栈是否为空
     boolean isEmpty()
     {
         return stack.isEmpty();
     }
     
     //打印栈元素
     public void display()
     {
         for(Object o:stack)
             System.out.println(o);
     }
}

  5、LinkedList的基本用法:

    推荐一篇介绍LinkedList基本用法的博文http://blog.csdn.net/i_lovefish/article/details/8042883,这里不再赘述。

  

 

    原文作者:温布利往事
    原文地址: https://www.cnblogs.com/xujian2014/p/4630785.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞