List介面(動態陣列)

南煎丸子發表於2020-07-27

List介面(動態陣列)

List集合類中元素有序且可重複

ArrayList(重要)

  • 作為List介面的主要實現類
  • 執行緒不安全的,效率高
  • 底層使用Object[] elementData陣列儲存

ArrayList的原始碼分析

jdk7

  1. 構造器

    ArrayList list = new ArrayList();

    • 底層建立了長度為10的Object[]陣列elementData
  2. 新增資料

    list.add(123)

    • 相當於elementData[0] = new Integer(123)
    • 底層的陣列長度為10,新增元素個數小於10時,正常新增元素
    • 新增的元素個數大於10後(底層elementData陣列容量不夠),則需要擴容,預設擴容為原來容量的1.5倍(相當於新造一個陣列,長度為原來長度的1.5倍)。同時需要將原來陣列的資料複製到新的陣列中

結論:建議使用帶參的構造器(避免在中間時擴容)

ArrayList list = new ArrayList(int capacity)

jdk8

  1. 構造器

    ArrayList list = new ArrayList();

    • 底層Object[] elementData初始化為{},並沒有建立長度為10的陣列
  2. 新增資料

    list.add(123)

    • 第一次add()時,底層才建立了長度為10的陣列,並將資料123新增到elementData[0]位置上
    • 後續的新增與擴容操作與jdk7相同

結論

  • jdk7中的ArrayList的物件的建立類似於單例模式中的餓漢式
  • jdk8中的ArrayList的物件的建立類似於單例模式中的懶漢式。延遲了陣列的建立,節省記憶體

LinkedList

  • 對於頻繁的插入、刪除操作,使用此類效率比ArrayList高
  • 底層使用雙向連結串列儲存

LinkedList的原始碼分析

LinkedList list = new LinkedList();

內部宣告瞭Node型別的first和last屬性,預設值為null

list.add(123);

將123封裝到Node中,建立了Node物件

其中Node定義為(原始碼),體現了LinkedList雙向連結串列的特徵:

private static class Node<E> {
        E item;
        LinkedList.Node<E> next;
        LinkedList.Node<E> prev;

        Node(LinkedList.Node<E> prev, E element, LinkedList.Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

Vector(不常用)

  • 作為List介面的古老實現類
  • 執行緒安全的、效率低
  • 底層使用Object[] elementData陣列儲存

Vector原始碼分析

  • jdk7和jdk8中通過Vector()構造器建立物件時,底層都建立了長度為10的陣列
  • 預設擴容為原來陣列長度的2倍

三者異同

相同點

三個類都實現了List介面,儲存資料的特點相同(有序、可重複的資料)

不同點

  • 底層不同
  • 不同情況下效率不同
  • 執行緒安全問題

List介面中常用的方法

Collection中的方法都可用

  1. add(int index , Object eles)

    在index位置開始,將eles中的所有元素新增進來

    ArrayList list = new ArrayList();
    list.add(123);
    list.add("Ann");
    list.add(new Students("Tom",18,90));
    list.add(987);
    
    list.add(3,"AA");
    System.out.println(list);//[123, Ann, Students{name='Tom', age=18, grade=90.0}, AA, 987]
    
  2. addAll(int index , Collection eles)

    從index位置開始將eles中的所有元素新增進來

    ArrayList list = new ArrayList();
    list.add(123);
    list.add("Ann");
    list.add(new Students("Tom",18,90));
    list.add(987);
    
    ArrayList arrayList = new ArrayList();
    arrayList.add(123);
    arrayList.add("Lisa");
    
    list.addAll(arrayList);
    System.out.println(list);//[123, Ann, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa]
    

注意使用的是add()還是addAll():

  • add()方法中將新增的元素看成一個整體,無論eles中有多少個元素,新增後的元素個數就是+1
  • addAll()方法中eles中有多少個元素,新增後就多多少個元素
  1. get(int index)

    獲取指定index位置的元素

    System.out.println(list.get(1));//Ann
    
  2. indexOf(Object obj)

    返回obj在當前集合中首次出現的位置

    System.out.println(list.indexOf(123));//0
    
    • 若存在該元素,返回其第一次出現的位置
    • 若不存在該元素,返回-1
  3. lastIndexOf(Object obj)

    返回obj在當前集合中最後一次出現的位置

    System.out.println(list.lastIndexOf(123));//4
    
    • 若存在該元素,返回其最後一次出現的位置
    • 若不存在該元素,返回-1
  4. remove(int index)

    移除指定index位置元素,並返回此元素

    System.out.println(list.remove(1));//Ann
    System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa]
    

    注意和Collection介面中的remove方法區分

  5. set(int index , Object ele)

    設定指定index位置的元素為ele

    System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa]
    list.set(2,789);
    System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 789, 123, Lisa]
    
  6. subList(int fromIndex , int toIndex)

    返回從fromIndex到toIndex位置的子集合(左閉右開)

    System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 789, 123, Lisa]
    System.out.println(list.subList(1, 3));//[Students{name='Tom', age=18, grade=90.0}, 789]
    

總結

  • 增:add(Object obj)

  • 刪:remove(int index)、remove(Object obj)

  • 改:set(int index , Object obj)

  • 查:get(int index)

  • 插:add(int index , Object obj)

  • 長度:size()

  • 遍歷

    ① Iterator迭代器方式

    ②增強for迴圈

    ③普通迴圈

注:區分remove方法(形參)

  • List介面中remove方法要求裡面的形參是int型別
  • Collection介面中remove方法要求裡面的形參是物件
  • 若list中元素為1,2,3;remove(2)表明移除位置為2的元素;若想要移除元素2,需要remove(new Integer(2))

相關文章