集合:List介面的實現類(ArrayList、LinkedList、Vector)

1、List介面

(1)特點

  • 有序(插入和取出的順序相等,因為有一個整數索引記錄了元素的插入的位置)
  • 允許有重複的元素(調用equals方法返回true,允許有多個null)
    @Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(null);
             list.add(111);
             list.add(null);
             System.out.println(list);
    }
[123, 123, null, 111, null]

(2)與collection相比的特有方法

  • add(index,元素):在指定的位置插入
  • get(index):獲取指定位置的元素
  • remove(index):刪除指定位置的元素
  • set(index,新元素):修改指定位置的元素
  • subList(index,index):根據索引範圍截取一個子集合
  • indexOf(元素):查找

與collection介面的最大區別就是list介面的操作會涉及到索引。

 

2、List介面的特有方法

(1)增加元素

指定位置插入

    @Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(null);
             list.add(111);
             list.add(null);
             list.add(1,"zhai");
             System.out.println(list);
    }
[123, zhai, 123, null, 111, null]

(2)下標越界異常

    @Test
    public void test1() {
             List list=new ArrayList();
             list.add(1,"zhai");
             System.out.println(list);
    }
java.lang.IndexOutOfBoundsException: Index: 1, Size: 0

程式源碼:

判斷索引的範圍是否有效:

 索引大於集合大小或索引小於0,拋出異常:

 

 (2)刪除元素

根據索引刪除:

@Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(null);
             list.add(111);
             list.add(null);
             list.remove(2);
             System.out.println(list);
    }
[123, 123, 111, null]

默認按照索引刪除:

@Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(1);
             list.remove(1);
             System.out.println(list);
    }
[123, 8848, 111, 1]

在可以按照索引刪除和按照元素刪除的情況下,List默認按照索引刪除元素

 編譯器提示的也是按照索引刪除,因為不存在100索引,會拋出異常:

java.lang.IndexOutOfBoundsException: Index: 100, Size: 5

 查看源碼可以看出remove存在方法的重載,index是基本數據類型的數據,如果是按照內容移除還要講int類型轉換為Integer類型,顯然是不合理的

 @Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
             list.remove(new Integer(100));
             System.out.println(list);
    }
[123, 123, 8848, 111]

直接傳遞引用類型的數據,不會再調用參數列表為int類型的remove方法,而是直接調用按照內容移除元素的方法

總結:

如果元素的類型為int的,默認按照索引刪除;如果想要按照指定的元素刪除,則需要裝箱後再刪除

(3)修改

(1)修改指定位置的元素:

@Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
             list.set(1,"2020年8月5日08:41:50");
             System.out.println(list);
    }
[123, 2020年8月5日08:41:50, 8848, 111, 100]

(4)查找

@Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
             System.out.println(list.indexOf(100));
    }
4

 

3、list介面的遍歷方式

(1)迭代器

  @Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
        Iterator iterator=list.iterator();
        while (iterator.hasNext()){
            Object l=iterator.next();
            System.out.println(l);
        }
    }
123
123
8848
111
100

(2)增強for

 @Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
             for (Object l:list){
                 System.out.println(l);
             }
    }
123
123
8848
111
100

(3)普通for

@Test
    public void test1() {
             List list=new ArrayList();
             list.add("123");
             list.add("123");
             list.add(8848);
             list.add(111);
             list.add(100);
             for (int i=0;i<list.size();i++){
                 System.out.println(list.get(i));
             }

    }
123
123
8848
111
100

因為list介面可以操作索引,因此,可以採用for循環遍歷list介面的數據

 

4、ArrayList源碼分析與底層結構

(1)可變長度的實現

程式碼:

@Test
    public void test1() {
             ArrayList list=new ArrayList();
             for (int i=0;i<=10;i++){
                 list.add("join"+i);
             }
                for (int i=11;i<=20;i++){
                    list.add("join"+i);
                }
                System.out.println(list);
    }

運行至集合中有10個元素:

 

 底層實際上是可變數組,該數組是Object類型的,初始的時候數組的長度為0,第一次擴容為10,第二次為15,第三次增加為22… … 也就是說數組的長度以1.5倍的速度增加

源碼分析:

 因為該變數是一個長度為0的數組:

 add方法:

 

 數組的擴容:

 elementData是存儲集合的可變數組:

 

 

5、Vector底層與ArrayList的對比

(1)相同點

底層都是可變數組

(2)不同點

版本:

  • ArrayList:新
  • Vector:舊

執行緒安全:

  • ArrayList:執行緒不安全,效率高
  • Vector:執行緒安全(同步),效率低

擴容倍數:

  • Vector變為原來的2倍

  •  Arraylist:變為原來的1.5倍

 

6、LinkedList底層和源碼分析

(1)LinkedList

底層是雙向鏈表

  • 每個結點維護三個屬性:item代表自己,next代表下一個元素,prev代表前一個元素
  • LinkedList維護兩個重要屬性:first和last,分別指向首結點和尾結點

(2)源碼分析

 構造器為空:

  public LinkedList() {
    }

添加元素的源碼分析:

   public boolean add(E e) {
        linkLast(e);
        return true;
    }
void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

new Node<>(l, e, null):三個參數分別是:前一個、當前元素、下一個

尾插法添加元素,第一次添加first就是第一個元素,不為空的時候在last後添加

(3)與ArrayList的對比

底層結構

ArrayList:可變數組

LinkedList:雙向鏈表

增刪的效率

ArrayList:需要移動大量的元素效率較低

LinkedList:插入時不需要移動記憶體中的元素,只需要改變引用的指向即可,所以插入或刪除的效率高

改查的效率

ArrayList:具有索引,查詢或修改快

LinkedList:查詢時從頭部開始,一個一個地找,查詢效率較低

使用場景

ArrayList:使用在查詢比較多,插入刪除較少的情況

LinkedList:使用在查詢比較少,插入和刪除比較多的情況

 

 

總結:

1、List的介面的三個實現類的選擇

如果考慮執行緒安全的問題,採用Vector

不考慮執行緒安全的問題的話,如果查詢較多用ArrayList,增刪較多用LinkedList

 

Tags: