摘要:重要方法在鏈尾添加元素除了這個方法以外,還提供了等一些方法,都是為實現(xiàn)和方法服務的,因為雙向鏈表的原因,這些實現(xiàn)都很簡單。
類聲明
LinkedList類聲明如下:
public class LinkedListextends AbstractSequentialList implements List , Deque , Cloneable, java.io.Serializable
可以發(fā)現(xiàn) LinkedList繼承了 AbstractSequentialList抽象類,而不是像 ArrayList和 Vector那樣實現(xiàn) AbstractList,實際上,java類庫中只有 LinkedList繼承了這個抽象類,正如其名,它提供了對序列的連續(xù)訪問的抽象:
LinkedList的底層是 Deque雙向鏈表,實現(xiàn)了 Deque接口,而 Deque接口繼承于 Queue接口,因此,在java中,如果要實現(xiàn)隊列,一般都使用 LinkedList來實現(xiàn)。
LinkedList中關于鏈表結點的定義如下:
private static class Node{ E item; Node next; Node prev; Node(Node prev, E element, Node next) { this.item = element; this.next = next; this.prev = prev; } }
每個結點都有一個前驅和后繼結點,并且在 LinkedList中也定義了兩個變量分別指向鏈表中的第一個和最后一個結點:
transient Node構造方法first; transient Node last;
LinkedList中只有兩個構造方法,無參數(shù)的和帶有 Collection參數(shù)的:
public LinkedList() { } public LinkedList(Collection extends E> c) { this(); addAll(c); }
重點看一下第二個構造方法,它調用了 addAll():
public boolean addAll(Collection extends E> c) { return addAll(size, c); }
這個方法將指定的 Collection添加到鏈表的結尾,如果在添加的過程中對 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; Nodepred, succ; if (index == size) { //如果succ是null,說明是在結尾添加,如果不是,記錄index處的結點 succ = null; pred = last; } else { succ = node(index); pred = succ.prev; } for (Object o : a) {// 雙向鏈表的插入操作 @SuppressWarnings("unchecked") E e = (E) o; Node 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; }
注意最終調用的是這個 addAll方法,這個方法是在指定位置 index 插入 Collection,使鏈表后面的元素右移,第一個 addAll中傳入的 index是 size,因此就是在結尾添加。
重要方法 add:在鏈尾添加元素public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Nodel = last; final Node newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
除了這個 linkLast方法以外,還提供了 linkFirst linkBefore unLink unLinkFirst等一些方法,都是為實現(xiàn) add和 remove方法服務的,因為雙向鏈表的原因,這些實現(xiàn)都很簡單。
clear因為底層實現(xiàn)不是數(shù)組,LinkedList中的 clear方法稍微復雜一些:
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 for (Nodex = first; x != null; ) { Node next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; }
clear方法中逐一取出每個結點,然后將它們的 item pre next都設為 null,有時候看以來不必要,但是為了防止在GC中,這些結點寄居在不同的年代中,因此最好這么做。
clone先看 clone方法的實現(xiàn):
public Object clone() { LinkedListclone = superClone(); // Put clone into "virgin" state clone.first = clone.last = null; clone.size = 0; clone.modCount = 0; // Initialize clone with our elements for (Node x = first; x != null; x = x.next) clone.add(x.item); return clone; } @SuppressWarnings("unchecked") private LinkedList superClone() { try { return (LinkedList ) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
可以看到, LinkedList的 Clone方法只是簡單的將原來每個 node的 item放到克隆后的對象中,和 ArrayList的 clone方法一樣, LinkedList的 Clone方法也只是淺復制,如果元素為引用類型,那么修改原 list的值會影響克隆的 list的值。
迭代元素如果仔細觀察,你會發(fā)現(xiàn)在 LinkedList中是沒有自己實現(xiàn) iterator的,如果這樣調用:
LinkedListlist = new LinkedList<>(); Iterator it = list.iterator();
你會發(fā)現(xiàn)它調用的是 AbstractSequentialList中的 iterator(),返回的還是 AbstractList 中的 listIterator(),而在 LinkedList中實現(xiàn)了自己的 listIterator,因此如果進行迭代,還是老老實實用 LinkedList中的 listIterator比較好。
LinkedList中還提供了逆序的 Iterator—— DescendingIterator,實際上它也只是簡單的對 ListIterator進行了封裝:
private class DescendingIterator implements Iterator和ArrayList的區(qū)別{ private final ListItr itr = new ListItr(size()); public boolean hasNext() { return itr.hasPrevious(); } public E next() { return itr.previous(); } public void remove() { itr.remove(); } } public Iterator descendingIterator() { return new DescendingIterator(); }
這里只是說一下大致的區(qū)別:
ArrayList繼承于 AbstractList, LinkedList繼承于 AbstractSequentialList;
ArrayList基于數(shù)組, LinkedList基于雙向鏈表,對于隨機訪問, ArrayList比較占優(yōu)勢,對于插入刪除,LinkedList占優(yōu)勢;
LinkedList沒有實現(xiàn)自己的 Iterator,但是有 ListIterator和 DescendingIterator;
LinkedList需要更多的內存,因為 ArrayList的每個索引的位置是實際的數(shù)據,而 LinkedList中的每個節(jié)點中存儲的是實際的數(shù)據和前后節(jié)點的位置;
ArrayList 和 LinkedList都是非同步的集合。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64471.html
摘要:是非,而是,這意味著是線程安全的,多個線程可以共享一個而如果沒有正確的同步的話,多個線程是不能共享的。另一個區(qū)別是的迭代器是迭代器,而的迭代器不 這里只解析一些常用的、比較重要的一些集合類,并且作者水平有限,有些地方可能解析不到位或者解析錯誤,還望各位讀者指出錯誤。 Collection List ArrayList LinkedLis...
面試舊敵之紅黑樹(直白介紹深入理解) - Android - 掘金 讀完本文你將了解到: 什么是紅黑樹 黑色高度 紅黑樹的 5 個特性 紅黑樹的左旋右旋 指定節(jié)點 x 的左旋 右圖轉成左圖 指定節(jié)點 y 的右旋左圖轉成右圖 紅黑樹的平衡插入 二叉查找樹的插入 插入后調整紅黑樹結構 調整思想 插入染紅后... java 多線程同步以及線程間通信詳解 & 消費者生產者模式 & 死鎖 & Thread...
摘要:它們會在鏈表為空時,拋出獲取尾節(jié)點數(shù)據方法兩者區(qū)別方法在鏈表為空時,會拋出,而則不會,只是會返回。 目錄: 0-1. 簡介 0-2. 內部結構分析 0-3. LinkedList源碼分析 0-3-1. 構造方法 0-3-2. 添加add方法 0-3-3. 根據位置取數(shù)據的方法 0-3-4. 根據對象得到索引的方法 0-3-5. 檢查鏈表是否包含某對象的方法 ...
摘要:介紹是線程不安全的,允許元素為的雙向鏈表。構造方法共有兩個構造方法,一個是創(chuàng)建一個空的構造函數(shù),一個是將已有的添加到中。是將元素插入到的頭部。下一篇文章繼續(xù)分析上次分析了的結構和添加方法這次開始分析下面的。注意源碼版本為直接進入正題。 如果本文中有不正確的地方請指出由于沒有留言可以在公眾號添加我的好友共同討論。 1.介紹 LinkedList 是線程不安全的,允許元素為null的雙向鏈...
摘要:在次操作中其實即尾節(jié)點是共享資源,當多個線程同時執(zhí)行此方法的時候,其實會出現(xiàn)線程安全問題。同樣會出現(xiàn)并發(fā)安全問題,下面對此問題進行分析。 1.LinkedList源碼分析 LinkedList的是基于鏈表實現(xiàn)的java集合類,通過index插入到指定位置的時候使用LinkedList效率要比ArrayList高,以下源碼分析是基于JDK1.8. 1.1 類的繼承結構 LinkedLis...
閱讀 1419·2021-09-22 15:52
閱讀 1459·2019-08-30 15:44
閱讀 895·2019-08-30 14:24
閱讀 2705·2019-08-30 13:06
閱讀 2700·2019-08-26 13:45
閱讀 2782·2019-08-26 13:43
閱讀 1015·2019-08-26 12:01
閱讀 1436·2019-08-26 11:56