1. 程式人生 > >ArrayList和LinkedList的用法區別

ArrayList和LinkedList的用法區別

  1. ArrayList是實現了基於動態陣列的資料結構,LinkedList基於連結串列的資料結構。
  2. 對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指標。
  3. 對於新增和刪除操作add和remove,LinedList比較佔優勢,因為ArrayList要移動資料。
    這一點要看實際情況的。若只對單條資料插入或刪除,ArrayList的速度反而優於LinkedList。但若是批量隨機的插入刪除資料,LinkedList的速度大大優於ArrayList. 因為ArrayList每插入一條資料,要移動插入點及之後的所有資料。 這一點我做了實驗。在分別有200000條“記錄”的ArrayList和LinkedList的首位插入20000條資料,LinkedList耗時約是ArrayList的20分之1。
for(int m=0;m<20000;m++){
        linkedlist.add(m,null);      //當在200000條資料之前插入20000條資料時,LinkedList只用了1125多ms.這就是LinkedList的優勢所在
        }
        long time4 = new Dte().getTime();
        System.out.print("batch linkedlist add:");
        System.out.println(time4 - time3);
        for(int n=0;n<20000;n++){
        arraylist.add(n, null
); //當在200000條資料之前插入20000條資料時,ArrayList用了18375多ms.時間花費是arraylist的近20倍(視測試時機器效能) } long time5 = new Date().getTime(); System.out.print("batch arraylist add:"); System.out.println(time5 - time4);
  1. 查詢操作indexOf,lastIndexOf,contains等,兩者差不多。
    5.隨機查詢指定節點的操作get,ArrayList速度要快於LinkedList.
    這裡只是理論上分析,事實上也不一定,ArrayList在末尾插入和刪除資料的話,速度反而比LinkedList要快。我做過一個插入和刪除200000條資料的試驗。
long time1 = new Date().getTime();
        String s1 = (String) linkedlist.get(100000);//  總記錄200000,linkedlist載入第100000條資料耗時15~32ms不等
        long time2 = new Date().getTime();
        System.out.println(time2 - time1);
        String s2 = (String) arraylist.get(100000);//  總記錄200000,linkedlist載入第100000條資料耗時0ms
        long time3 = new Date().getTime();
        System.out.println(time3 - time2);
 /*分別insert200000條資料到linkedlist和arraylist
    *由於是在末尾插入資料,arraylist的速度比linkedlist的速度反而要快 
    */
    public static void insertList(LinkedList linklist, ArrayList arraylist) {
        long time1 = new Date().getTime();
        System.out.println(time1);
        for (int i = 0; i < 200000; i++) {
            linklist.add(i, "linklist" + i);
        }
        long time2 = new Date().getTime();
        System.out.println(time2 - time1);
        for (int j = 0; j < 200000; j++) {
            arraylist.add(j, "arraylist" + j);
        }
        long time3 = new Date().getTime();
        System.out.println(time3 - time2);
    }


/*delete linkedlist和arraylist中的200000條資料
    *由於是在末尾刪除資料,arraylist的速度比linkedlist的速度反而要快 
    */
    public static void deleteList(LinkedList linklist, ArrayList arraylist) {
        long time1 = new Date().getTime();
        System.out.println(time1);
        for (int i = 199999; i >= 0; i--) {
            linklist.remove(i);
        }
        long time2 = new Date().getTime();
        System.out.println(time2 - time1);
        for (int j = 199999; j >= 0; j--) {
            arraylist.remove(j);
        }
        long time3 = new Date().getTime();
        System.out.println(time3 - time2);
    }

    public static void main(String args[]) {
        LinkedList linkedlist = new LinkedList();
        ArrayList arraylist = new ArrayList();
        insertList(linkedlist, arraylist);

插入:
LinkedList 578ms
ArrayList 437ms
刪除:
LinkedList 31ms
ArrayList 16ms

比較一下ArrayList和LinkedList
1.ArrayList是基於陣列,LinkedList基於連結串列實現。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指標。
3.對於新增和刪除操作add和remove,LinedList比較佔優勢,因為ArrayList要移動資料。
4.查詢操作indexOf,lastIndexOf,contains等,兩者差不多。
這裡只是理論上分析,事實上也不一定,比如ArrayList在末尾插入和刪除資料就不設計到資料移動,不過還是
有這麼個建議:隨機訪問比較多的話一定要用ArrayList而不是LinkedList,如果需要頻繁的插入和刪除應該
考慮用LinkedList來提高效能。

如果z 引用一個當前內容是“start”的字串緩衝區物件,則此方法呼叫 z.append(“le”) 會使字串緩衝區包含“startle”,而 z.insert(4, “le”) 將更改字串緩衝區,使之包含“starlet”。

每個字串緩衝區都有一定的容量。只要字串緩衝區所包含的字元序列的長度沒有超出此容量,就無需分配新的內部緩衝區陣列。如果內部緩衝區溢位,則此容量自動增大。從 JDK 5 開始,為該類補充了一個單個執行緒使用的等價類,即 StringBuilder。與該類相比,通常應該優先使用 StringBuilder 類,因為它支援所有相同的操作,但由於它不執行同步,所以速度更快。 例如:如果 sb 引用 StringBuilder 的一個例項,則 sb.append(x) 和 sb.insert(sb.length(), x) 具有相同的效果。Java.lang.StringBuilder一個可變的字元序列。此類提供一個與 StringBuffer 相容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字串緩衝區被單個執行緒使用的時候(這種情況很普遍)。如果可能,建議優先採用該類,因為在大多數實現中,它比 StringBuffer 要快。在 StringBuilder 上的主要操作是 append 和 insert 方法,可過載這些方法,以接受任意型別的資料。每個方法都能有效地將給定的資料轉換成字串,然後將該字串的字元追加或插入到字串生成器中。 append 方法始終將這些字元新增到生成器的末端;而 insert 方法則在指定的點新增字元。

String / StringBuffer /StringBuilder,在字串連線操作上效能依次加強,我曾經做過一個實驗,連續進行10000次的字串操作,三者速度上的差距是驚人的。在確切知道是不變字串的情況下,還是用String最好,因為Java語言中String採用了享元模式(Flyweight),在JVM中只存在一份相同的String 。在確定迴圈次數時,儘量使用for迴圈,在迴圈巢狀中儘量將大迴圈放到外層,小迴圈放到內層,這點與VB等語言恰好相反,經過程式碼測試的,不過還不知道原因。總之,在VB等微軟系列語言中用小套大會快很多,而在JAVA中用大套小會快很多!當然這是指兩者能互相替換的時候,比如二維陣列遍覓等!

如果字串特別長,採用charAt逐一獲取特定位置的字元是非常耗時的。因為每次獲取制定索引位置的字元都要引起新的檢索過程,更好的辦法是將字串通過呼叫toCharArray方法轉換成字元陣列,然後通過陣列索引值獲得指定位置的字元。

對於boolean值,避免不必要的等式判斷將一個boolean值與一個true比較是一個恆等操作(直接返回該boolean變數的值). 移走對於boolean的不必要操作至少會帶來2個好處: 1)程式碼執行的更快 (生成的位元組碼少了5個位元組); 2)程式碼也會更加乾淨。

關於使用SESSION問題上,儘量不要將大物件放到HttpSession或其他須序列化的物件中,並注意及時清空Session。

ArrayList容量擴容問題

1. 底層使用陣列

private transient Object[] elementData;

一個物件只要實現了Serilizable介面,這個物件九二可以被序列化,java的這種序列化模式為開發者提供了很多遍歷,讓開發者不必關心具體序列化的過程。
實際開發中某些屬性不需要序列化,如敏感資訊(password. card NO),為安全起見,不希望在網路上操作中被傳輸,就可以使用transient關鍵字修飾。

2.transient使用小結

1)一旦變數被transient修飾,變數將不再是物件持久化的一部分,該變數內容在序列化後無法獲得訪問。

2)transient關鍵字只能修飾變數,而不能修飾方法和類。注意,本地變數是不能被transient關鍵字修飾的。變數如果是使用者自定義類變數,則該類需要實現Serializable介面。

3)被transient關鍵字修飾的變數不再能被序列化,一個靜態變數不管是否被transient修飾,均不能被序列化。

3.構造哈數
ArrayList():預設建構函式,提供初始容量為10的空列表。

ArrayList(int initialCapacity):構造一個具有指定初始容量的空列表。

ArrayList(Collection

public void ensureCapacity(int minCapacity) {
        //修改計時器
        modCount++;
        //ArrayList容量大小
        int oldCapacity = elementData.length;
        /*
         * 若當前需要的長度大於當前陣列的長度時,進行擴容操作
         */
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            //計算新的容量大小,為當前容量的1.5倍
            int newCapacity = (oldCapacity * 3) / 2 + 1;
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            //陣列拷貝,生成新的陣列
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

每次擴容1.5倍。
處理這個ensureCapacity()這個擴容陣列外,ArrayList還給我們提供了將底層陣列的容量調整為當前列表儲存的實際元素的大小的功能。它可以通過trimToSize()方法來實現。該方法可以最小化ArrayList例項的儲存量。

public void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (size < oldCapacity) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }