後端---Java中ArrayList和LinkedList區別和聯繫

ArrayList和LinkedList的區別和聯繫

在一個多月之前,我曾寫過一篇博客想要迅速簡潔的瞭解Java中所有的集合類型(List、Set、Map),然後一個月多後的我不得已又抱起《Java核心卷I 》仔細研讀,這是爲什麼呢???

是因爲“溫故而知新”還是因爲“書讀百遍其義自顯”????

都不是!!!

因爲我忘完了啊!

關於List和Set、Map的博客,這裏給出鏈接 

 java中List、Set、Map之間的關係 https://blog.csdn.net/weixin_42504145/article/details/83119088

一.初識List 

首先我們從一副圖來看ArrayLIst和LinkedList的關係,很明顯他兩都實現了Java給出的List集合這個接口,但是我要說的是這個圖並不完善!!!

我們來看完善的定義: 

// lang java
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Queue<E>, Cloneable, Serializable

從繼承關係來看:

在這個引用中我們能看到的ArrayList集成了AbstractList這個父類,雖然Linkedlist繼承的是AbstractSequentialList這個父類,但這個父類仍繼承與AbstactList這個類,所有並沒有太大區別。 

從接口實現關係來看:

聯繫:無論是ArrayList和LinkedList都實現了List<E>、Cloneable、Serializable這三個接口。List接口會作爲重點在下面詳細介紹,先來看另外兩個接口,Cloneable接口是一個標記接口,也就是沒有任何內容,這裏分析一下這個接口的用法,clone方法是在Object種定義的,而且是protected型的,只有實現了這個接口,纔可以在該類的實例上調用clone方法,否則會拋出CloneNotSupportException。Object中默認的實現是一個淺拷貝,也就是表面拷貝,如果需要實現深層次拷貝的話,必須對類中可變域生成新的實例。Serializable接口是一個對象序列化的接口,一個類只有實現了Serializable接口,它的對象才能被序列化。

區別:ArrayList實現了隨機訪問的接口RandomAccess,LinkedList實現了Quene的接口。ArrayList是基於動態數組實現的list,而LinkedList是基於鏈表實現的list。所以,ArrayList擁有着數組的特性,LinkedList擁有着鏈表的特性。

我們再來看List這個接口

 List集合是一個有序集合。元素會增加到容器中的特定位置。可以採用兩種方式訪問元素:使用迭代器訪問,或者使用一個整數索引來訪問。後一種方式稱爲隨機訪問,因爲這樣可以按任意順序訪問元素。與之不同的是,使用迭代器訪問時,必須順序地訪問元素。

List接口定義了多個用於隨即訪問的訪問:

void add(int index,E element)

void remove(int index)

E get(int index)

E set(int index,E element)

二. ArrayList和LinkedList

ArrayList 

ArrayList實現了List接口,它是以數組的方式來實現的,數組的特性是可以使用索引的方式來快速定位對象的位置,因此對於快速的隨機取得對象的需求,使用ArrayList實現執行效率上會比較好. 

ArrayListDemo:

public class ArrayListDemo {  
  
    public static void main(String[] args) {  
          
        List<String> userlist = new ArrayList<String>();  
        userlist.add("yulon");  
        userlist.add("xiaoyun");  
        userlist.add("羽龍共舞");  
        System.out.println("使用普通for循環:");  
        for(int i=0; i<userlist.size(); i++){  
            System.out.print(userlist.get(i)+" ");  
        }  
        System.out.println();  
        System.out.println();  
        System.out.println("使用Iterator迭代器:");  
        Iterator it = userlist.iterator();  
        while(it.hasNext()){  
            System.out.print(it.next()+" ");  
        }  
        System.out.println();  
        System.out.println();  
        System.out.println("使用增強for循環:");  
          
        for(String s : userlist){  
            System.out.print(s+" ");  
        }  
    }  
}  

這裏有三種輸出輸出List的方法,我們不建議用for循環輸出List,因爲在下面的例子中用for循環輸出LinkedList會造成一個很嚴重的失誤,因爲LinkedList底層是用鏈表實現的,如果使用get()方法獲取某個元素的值,LinkedList每次都會從頭開始遍歷極其損耗性能,我們建議用Iterator和for-each方法來輸出List集合,關於for-each方法內部也是生存成了一個Iterator對象,只不過在底層進行了封裝,我們看不見而已。如果關於Iterator不懂的可以參考我這篇博客:

https://blog.csdn.net/weixin_42504145/article/details/85210723  Java中Iterator(迭代器)的用法及其背後機制的探究

LinkedList

LinkedList是採用鏈表的方式來實現List接口的,它本身有自己特定的方法,如: addFirst(),addLast(),getFirst(),removeFirst()等. 由於是採用鏈表實現的,因此在進行insert和remove動作時在效率上要比ArrayList要好得多!適合用來實現Stack(堆棧)與Queue(隊列),前者先進後出,後者是先進先出.

public class StringStack {  
    private LinkedList<String> linkedList   
    = new LinkedList<String>();  
  
    /** 
     * 將元素加入LinkedList容器 
     * (即插入到鏈表的第一個位置) 
     */  
    public void push(String name){  
        linkedList.addFirst(name);  
    }  
    /** 
     * 取出堆棧中最上面的元素 
     * (即取出鏈表linkedList的第一個元素) 
     * @return 
     */  
    public String getTop(){  
        return linkedList.getFirst();  
    }  
    /** 
     * 取出並刪除最上面的元素 
     * (即移出linkedList的第一個元素) 
     * @return 
     */  
    public String pop(){  
        return linkedList.removeFirst();  
    }  
    /** 
     * 獲取元素個數 
     * @return 
     */  
    public int size(){  
        return linkedList.size();  
    }  
      
    /** 
     * 判斷堆棧是否爲空 
     * (即判斷 linkedList是否爲空) 
     * @return 
     */  
    public boolean isEmpty(){  
        return linkedList.isEmpty();  
    }  
    //測試  
    public static void main(String[] args) {  
        StringStack stack = new StringStack();  
        stack.push("yulon");  
        stack.push("xiaoyun");  
        stack.push("羽龍共舞");  
        System.out.print("第一個元素是:\t");  
        System.out.println(stack.getTop());  
        System.out.println();  
        System.out.println("全部元素:");  
        while(!stack.isEmpty()){  
            System.out.println("\t"+stack.pop());  
        }  
    }  
}  

三.總結 

下面這些區別是我們都知道的:

   1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。 (LinkedList是雙向鏈表,有next也有previous)
     2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針。 
     3.對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。 

我們再來自己總結總結ArrayList和LinkedList的區別: 

ArrayList和LinkedList在性能上各有優缺點,都有各自所適用的地方,總的說來可以描述如下: 

  • 對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。
  • 在ArrayList的中間插入或刪除一個元素意味着這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
  • LinkedList不支持高效的隨機元素訪問。
  • ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間
  • 可以這樣說:當操作是在一列數據的後面添加數據而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數據的前面或中間添加或刪除數據,並且按照順序訪問其中的元素時,就應該使用LinkedList了。

 

 

 

參考鏈接:
https://blog.csdn.net/bjzhuhehe/article/details/72230559

https://www.cnblogs.com/Jacck/p/8034900.html

https://www.cnblogs.com/lxq0309/p/3655742.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章