Java 容器和泛型(2)ArrayList 、LinkedList和Vector比較
一、List回顧
序列(List),有序的Collection,正如它的名字一樣,是一個有序的元素列表。確切的講,列表通常允許滿足 e1.equals(e2) 的元素對 e1 和 e2,並且如果列表本身允許 null 元素的話,通常它們允許多個 null 元素。實現List的有:ArrayList、LinkedList、Vector、Stack等。值得一提的是,Vector在JDK1.1的時候就有了,而List在JDK1.2的時候出現,待會我們會聊到ArrayList和Vector的區別。
二、ArrayList vs. Vector
ArrayList是一個可調整大小的陣列實現的序列。隨著元素增加,其大小會動態的增加。此類在Iterator或ListIterator迭代中,呼叫容器自身的remove和add方法進行修改,會丟擲ConcurrentModificationException併發修改異常。
注意,此實現不是同步的。如果多個執行緒同時訪問一個 ArrayList 例項,而其中至少一個執行緒從結構上修改了列表,那麼它必須 保持外部同步。(結構上的修改是指任何新增或刪除一個或多個元素的操作,或者顯式調整底層陣列的大小;僅僅設定元素的值不是結構上的修改。)這一般通過對自然封裝該列表的物件進行同步操作來完成。如果不存在這樣的物件,則應該使用 Collections.synchronizedList
方法將該列表“包裝”起來。這最好在建立時完成,以防止意外對列表進行不同步的訪問:
List list = Collections.synchronizedList(new ArrayList(…));
下面演示下相關ArrayList例子。
ArrayList基本方法程式碼:
@SuppressWarnings({ "rawtypes", "unchecked" }) public static void listMethods() { List a1 = new ArrayList<String>(); a1.add("List01"); a1.add("List03"); a1.add("List04"); System.out.print("原來集合:/n/t"+a1+"/n"); a1.add(1,"List02"); System.out.print("指定角標1插入:/n/t"+a1+"/n"); a1.remove(2); System.out.print("指定角標2刪除:/n/t"+a1+"/n"); System.out.print("指定角標2查詢:/n/t"+a1.get(2)+"/n"); Iterator i1 = a1.iterator(); System.out.println("用迭代器查詢全部元素:"); while (i1.hasNext()) { System.out.print(i1.next()+","); } }
可以從控制檯可以看出:
原來集合: [List01, List03, List04] 指定角標1插入: [List01, List02, List03, List04] 指定角標2刪除: [List01, List02, List04] 指定角標2查詢: List04 用迭代器查詢全部元素: List01,List02,List04
在上面我們可以根據角標來增加(add)、刪除(remove)、獲取(get)列表裡面元素。ArrayList提供了Iterator迭代器來遍歷序列。值得注意的是,迭代器的就相當於一個指標指向角標,next()方法就相當於指標往後移一位。所以切記,用迭代器中一次迴圈用一次next()。
下面演示下在ConcurrentModificationException的出現,及處理方案。泥瓦匠用Iterator演示這個異常的出現:
@SuppressWarnings({ “unchecked”, “rawtypes” }) public static void iteratorTest() { List a1 = new ArrayList<String>(); a1.add(“List01″); a1.add(“List02″); a1.add(“List04″); a1.add(“List05″); Iterator i1 = a1.iterator(); while (i1.hasNext()) { Object obj = i1.next(); if (obj.equals(“List02″)) a1.add(“List03″); } System.out.print(“集合:/n/t”+a1+”/n”); }
執行,我們可以在控制檯看到:
怎麼解決的,先看清楚這個問題。問題描述很清楚,在建立迭代器之後,除非通過迭代器自身的 remove 或 add 方法從結構上對列表進行修改,否則在任何時間以任何方式對列表進行修改,迭代器都會丟擲ConcurrentModificationException
。
因此我們應該這樣修改程式碼,用ListIterator迭代器提供方法:
@SuppressWarnings({ "unchecked", "rawtypes" }) public static void listIterator() { List a1 = new ArrayList<String>(); a1.add("List01"); a1.add("List"); a1.add("List03"); a1.add("List04"); ListIterator l1 = a1.listIterator(); while (l1.hasNext()) { Object obj = l1.next(); if (obj.equals("List")) { l1.remove(); l1.add("List02"); } } System.out.print("集合:/n/t"+a1+"/n"); }
執行下,我們可以看到:
集合: [List01, List02, List03, List04]
這樣,我們成功解決了這個併發修改異常。把其中‘List’元素刪除,新增了一個‘List02’的元素。
Vector非常類似ArrayList。早在JDK1.1的時候就出現了,以前沒有所謂的List介面,現在此類被改進為實現List介面。但與新的Collection不同的是,Vector是同步的。泥瓦匠想說的是Vector,在像查詢的效能上會比ArrayList開銷大。下面演示下Vector的基本例子:
@SuppressWarnings({ "unchecked", "rawtypes" }) public static void vectorMethods() { Vector v1 = new Vector<String>(); v1.add("Vector001"); v1.add("Vector002"); v1.add("Vector003"); v1.add("Vector004"); v1.add("Vector005"); Enumeration e1 =v1.elements(); while (e1.hasMoreElements()) { Object object = e1.nextElement(); System.out.println(object); } }
從方法上看幾乎沒差別,同樣注意的是:此介面的功能與 Iterator 介面的功能是重複的。此外,Iterator 介面新增了一個可選的移除操作,並使用較短的方法名。新的實現應該優先考慮使用 Iterator 介面而不是 Enumeration 介面。
三、LinkedList及其與ArrayList效能比
LinkedList與ArrayList一樣實現List介面,LinkedList是List介面連結串列的實現。基於連結串列實現的方式使得LinkedList在插入和刪除時更優於ArrayList,而隨機訪問則比ArrayList遜色些。LinkedList實現所有可選的列表操作,並允許所有的元素包括null。除了實現 List 介面外,LinkedList 類還為在列表的開頭及結尾 get、remove 和 insert 元素提供了統一的命名方法。這些操作允許將連結列表用作堆疊、佇列或雙端佇列。
LinkedList和ArrayList的方法時間複雜度總結如下圖所示。
表中,新增add()指新增元素的方法,remove()是指除去(int index)角標。ArrayList具有O(N)的任意指數時間複雜度的新增/刪除,但O(1)的操作列表的末尾。連結串列的O(n)的任意指數時間複雜度的新增/刪除,但O(1)操作端/列表的開始。
泥瓦匠用程式碼驗證下這個結論:
public static void testPerBtwnArlAndLkl() { ArrayList<Integer> arrayList = new ArrayList<Integer>(); LinkedList<Integer> linkedList = new LinkedList<Integer>(); // ArrayList add long startTime = System.nanoTime(); long endTime; long duration; for (int i = 0; i < 100000; i++) { arrayList.add(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("ArrayList add: " + duration); // LinkedList add startTime = System.nanoTime(); for (int i = 0; i < 100000; i++) { linkedList.add(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("LinkedList add: " + duration); // ArrayList get startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { arrayList.get(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("ArrayList get: " + duration); // LinkedList get startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { linkedList.get(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("LinkedList get: " + duration); // ArrayList remove startTime = System.nanoTime(); for (int i = 9999; i >=0; i--) { arrayList.remove(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("ArrayList remove: " + duration); // LinkedList remove startTime = System.nanoTime(); for (int i = 9999; i >=0; i--) { linkedList.remove(i); } endTime = System.nanoTime(); duration = endTime - startTime; System.out.println("LinkedList remove: " + duration); }
控制檯輸出如下:
ArrayList add: 16904776 LinkedList add: 12015418 ArrayList get: 1304593 LinkedList get: 108950741 ArrayList remove: 787388127 LinkedList remove: 128145950
對比下的話,其效能差距很明顯。LinkedList在新增和刪除中效能快,但在獲取中效能差。從複雜度和測試結果,我們應該懂得平時在新增或者刪除操作頻繁的地方,選擇LinkedList時考慮:
1、沒有大量的元素的隨機訪問
2、新增/刪除操作
自然我下面用LinedList實現一個資料結構–棧。泥瓦匠留給大家LinkedList的一些方法自己消化下。
package com.sedion.bysocket.collection; import java.util.LinkedList; /** * 用LinkedList實現棧 * 佇列和棧區別:佇列先進先出,棧先進後出。 */ public class Stack<T> { private LinkedList<T> storage = new LinkedList<T>(); /** 入棧 */ public void push(T v) { storage.addFirst(v); } /** 出棧,但不刪除 */ public T peek() { return storage.getFirst(); } /** 出棧,刪除 */ public T pop() { return storage.removeFirst(); } /** 棧是否為空 */ public boolean empty() { return storage.isEmpty(); } /** 輸出棧元素 */ public String toString() { return storage.toString(); } public static void main(String[] args) { Stack stack=new Stack<String>(); stack.push("a"); stack.push("b"); stack.push("c"); System.out.println(stack.toString()); Object obj=stack.peek(); System.out.println(obj+"--"+stack.toString()); obj=stack.pop(); System.out.println(obj+"--"+stack.toString()); System.out.println(stack.empty()); } }
四、總結
泥瓦匠總結如下:
Vector和ArrayList
1、vector是執行緒同步的,所以它也是執行緒安全的,而arraylist是執行緒非同步的,是不安全的。
2、記住併發修改異常 java.util.ConcurrentModificationException ,優先考慮ArrayList,除非你在使用多執行緒所需。
Aarraylist和Linkedlist
1、對於隨機訪問get和set,ArrayList覺得優於LinkedList,LinkedList要移動指標。
2、於新增和刪除操作add和remove,LinedList比較佔優勢,ArrayList要移動資料。
3、單條資料插入或刪除,ArrayList的速度反而優於LinkedList.若是批量隨機的插入刪除資料,LinkedList的速度大大優於ArrayList. 因為ArrayList每插入一條資料,要移動插入點及之後的所有資料。
相關文章
- ArrayList和LinkedList的比較
- Java 容器和泛型(3)HashSet,TreeSet 和 LinkedHashSet比較Java泛型
- LinkedList和ArrayList的區別、Vector和ArrayList的區別
- java複習之 Vector、ArrayList和LinkedList 的區別Java
- Java List 常用集合 ArrayList、LinkedList、VectorJava
- Java 集合 ArrayList VS LinkedList VS VectorJava
- java中的List介面(ArrayList、Vector、LinkedList)Java
- Java 容器和泛型(1)認識容器Java泛型
- ArrayList和LinkedList區別 javaJava
- Go中泛型和反射比較指南Go泛型反射
- 說出 ArrayList,Vector, LinkedList 的儲存效能和特性?
- ArrayList 和 Vector 的區別 -JAVAJava
- Java中ArrayList和LinkedList區別Java
- Java中Vector和ArrayList的區別Java
- 【java】【集合】List的三個子類—ArrayList、Vector、LinkedList的區別和聯絡Java
- ARRAYLIST VECTOR LINKEDLIST 區別與用法
- C#中陣列Array、ArrayList、泛型List<T>的比較C#陣列泛型
- ArrayList、LinkedList和Vector的原始碼解析,帶你走近List的世界原始碼
- Vector和ArrayList的區別
- ArrayList和LinkedList的區別?
- ArrayList和LinkedList的區別
- ArrayList,LinkedList,Vector,Stack之間的區別
- Java集合和泛型Java泛型
- JAVA API:ArrayList(泛型類)基本使用JavaAPI泛型
- Java ArrayList 與 LinkedListJava
- LinkedList重寫(5)LinkedList簡單的封裝和增加泛型封裝泛型
- Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及區別Java
- Java泛型知識點:泛型類、泛型介面和泛型方法Java泛型
- ArrayList和LinkedList如何實現的?
- List集合總結,對比分析ArrayList,Vector,LinkedList
- 一道關於:ArrayList、Vector、LinkedList的儲存效能和特性 的面試題面試題
- Java和JavaSciprt比較Java
- 比較Windows和Linux SQL容器WindowsLinuxSQL
- Oracle date 型別比較和String比較Oracle型別
- java arrayList vector 區別Java
- java集合【12】——— ArrayList,LinkedList,Vector的相同點與區別是什麼?Java
- Java & Go 泛型對比JavaGo泛型
- ArrayList、Vector、LinkedList的區別及其優缺點? (轉載)