(轉載)Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比較

來源:互聯網
上載者:User

標籤:

繼續上一篇的容器文章認識容器,泥瓦匠慢慢帶你們走進List的容器解說。今天泥瓦匠想說說 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:  16904776LinkedList add: 12015418ArrayList get:  1304593LinkedList get: 108950741ArrayList remove:  787388127LinkedList 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的資料結構是三個對象,組大小恰當就會比鏈錶快吧,直接賦值就完了,不用再設定前後指標的值。
若是批量隨機的插入刪除資料,LinkedList的速度大大優於ArrayList. 因為ArrayList每插入一條資料,要移動插入點及之後的所有資料。

轉載自:http://www.bysocket.com/?p=169

(轉載)Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比較

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.