Java集合框架02:ArrayList(上)

ArrayList實踐

問題:我們現在有4只小狗,我們如何存儲它的信息,獲取總數,並能夠逐條打印狗狗信息!

分析:通過List 接口的實現類ArrayList 實現該需求

  • 元素個數不確定
  • 要求獲得元素的實際個數
  • 按照存儲順序獲取並打印元素信息

問題聯想:

  • 刪除第一個狗狗:remove(index)
  • 刪除指定位置的狗狗 :remove(object)
  • 判斷集合中是否包含指定狗狗 : contains(object)

分析:使用List接口提供的remove()、contains()方法

package com.arraylist;

import java.util.ArrayList;
import java.util.List;

class Dog{
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Demo01 {
    public static void main(String[] args) {
        //創建ArrayList對象,並存儲
        List dogs = new ArrayList();
        dogs.add(new Dog("狗1"));
        dogs.add(new Dog("狗2"));
        dogs.add(new Dog("狗3"));
        dogs.add(2,new Dog("狗4"));  //添加到指定位置
        Dog dog5 = new Dog("狗5");
        dogs.add(dog5);
        //.size(): ArrayList大小
        System.out.println(dogs.size());
        //刪除前
        for (int i = 0; i < dogs.size(); i++) {
            Dog dog = (Dog) dogs.get(i);
            System.out.println(dog.getName());
        }
        System.out.println("===========================");
        //刪除第一個狗狗
        dogs.remove(0);
        //刪除指定位置的狗狗:
        dogs.remove(dogs.get(2));
        //判斷集合中是否包含指定狗狗:
        System.out.println(dogs.contains(dog5));
        //.get(i): 逐個獲取元素
        for (int i = 0; i < dogs.size(); i++) {
            Dog dog = (Dog) dogs.get(i);
            System.out.println(dog.getName());
        }

    }
}

【常用方法】

在這裏插入圖片描述

ArrayList源碼分析

1、ArrayList概述

  1. ArrayList是可以動態增長和縮減的索引序列,它是基於數組實現的List類。
  2. 該類封裝了一個動態再分配的Object[]數組,每一個類對象都有一個capacity【容量】屬性,表示 它們所封裝的Object[]數組的長度,當向ArrayList中添加元素時,該屬性值會自動增加。如果想 ArrayList中添加大量元素,可使用ensureCapacity方法一次性增加capacity,可以減少增加重分配 的次數提高性能。
  3. ArrayList的用法和Vector向類似,但是Vector是一個較老的集合,具有很多缺點,不建議使用。

另外,ArrayList和Vector的區別是:ArrayList是線程不安全的,當多條線程訪問同一個ArrayList集合 時,程序需要手動保證該集合的同步性,而Vector則是線程安全的。

  1. ArrayList和Collection的關係:

在這裏插入圖片描述

2、ArrayList的數據結構

分析一個類的時候,數據結構往往是它的靈魂所在,理解底層的數據結構其實就理解了該類的實現思路,具體的實現細節再具體分析。

ArrayList的數據結構是:

在這裏插入圖片描述

說明:底層的數據結構就是數組,數組元素類型爲Object類型,即可以存放所有類型數據。我們對 ArrayList類的實例的所有的操作底層都是基於數組的。

3、ArrayList源碼分析

1、繼承結構和層級關係

IDEA快捷鍵:Ctrl+H

在這裏插入圖片描述

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
}

我們看一下ArrayList的繼承結構:

ArrayList extends AbstractList

AbstractList extends AbstractCollection

所有類都繼承Object 所以ArrayList的繼承結構就是上圖這樣。

【分析】

1.爲什麼要先繼承AbstractList,而讓AbstractList先實現List?而不是讓ArrayList直接實現List?

這裏是有一個思想,接口中全都是抽象的方法,而抽象類中可以有抽象方法,還可以有具體的實現方 法,正是利用了這一點,讓AbstractList是實現接口中一些通用的方法,而具體的類,如ArrayList就繼承 這個AbstractList類,拿到一些通用的方法,然後自己在實現一些自己特有的方法,這樣一來,讓代碼更 簡潔,就繼承結構最底層的類中通用的方法都抽取出來,先一起實現了,減少重複代碼。所以一般看到 一個類上面還有一個抽象類,應該就是這個作用。

  1. ArrayList實現了哪些接口?

List接口:我們會出現這樣一個疑問,在查看了ArrayList的父類 AbstractList也實現了List接口,那爲什 麼子類ArrayList還是去實現一遍呢?

這是想不通的地方,所以我就去查資料,有的人說是爲了查看代碼方便,使觀看者一目瞭然,說法不 一,但每一個讓我感覺合理的,但是在stackOverFlow中找到了答案,這裏其實很有趣。

開發這個collection 的作者Josh說:

這其實是一個mistake[失誤],因爲他寫這代碼的時候覺得這個會有用處,但是其實並沒什麼用,但因爲 沒什麼影響,就一直留到了現在。

RandomAccess接口:這個是一個標記性接口,通過查看api文檔,它的作用就是用來快速隨機存取, 有關效率的問題,在實現了該接口的話,那麼使用普通的for循環來遍歷,性能更高,例如ArrayList。而 沒有實現該接口的話,使用Iterator來迭代,這樣性能更高,例如linkedList。所以這個標記性只是爲了 讓我們知道我們用什麼樣的方式去獲取數據性能更好。

Cloneable接口:實現了該接口,就可以使用Object.Clone()方法了。

Serializable接口:實現該序列化接口,表明該類可以被序列化,什麼是序列化?簡單的說,就是能夠 從類變成字節流傳輸,然後還能從字節流變成原來的類。

2、類中的屬性

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 版本號
private static final long serialVersionUID = 8683452581122892189L;
// 缺省容量
private static final int DEFAULT_CAPACITY = 10;
// 空對象數組
private static final Object[] EMPTY_ELEMENTDATA = {};
// 缺省空對象數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素數組
transient Object[] elementData;
// 實際元素大小,默認爲0
private int size;
// 最大數組容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}

3、構造方法

通過IDEA查看源碼,看到ArrayList有三個構造方法:

在這裏插入圖片描述
\1. 無參構造方法

/*
Constructs an empty list with an initial capacity of ten.
這裏就說明了默認會給10的大小,所以說一開始arrayList的容量是10.
*/
//ArrayList中儲存數據的其實就是一個數組,這個數組就是elementData.
public ArrayList() {
super(); //調用父類中的無參構造方法,父類中的是個空的構造方法
this.elementData = EMPTY_ELEMENTDATA;
//EMPTY_ELEMENTDATA:是個空的Object[], 將elementData初始化,elementData
也是個Object[]類型。空的Object[]會給默認大小10,等會會解釋什麼時候賦值的。
}

\1. 有參構造方法 1

/*
Constructs an empty list with the specified initial capacity.
構造具有指定初始容量的空列表。
@param initialCapacity the initial capacity of the list
初始容量列表的初始容量
@throws IllegalArgumentException if the specified initial capacity is
negative
如果指定的初始容量爲負,則爲IllegalArgumentException
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
////將自定義的容量大小當成初始化 initialCapacity 的大小
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA; //等同於無參構造方法
} else {
////判斷如果自定義大小的容量小於0,則報下面這個非法數據異常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

\1. 有參構造方法 2

/*
Constructs a list containing the elements of the specified collection,
in the order they are returned by the collection's iterator.
按照集合迭代器返回元素的順序構造包含指定集合的元素的列表。
@param c the collection whose elements are to be placed into this list
@throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //轉換爲數組
//每個集合的toarray()的實現方法不一樣,所以需要判斷一下,如果不是Object[].class類
型,那麼久需要使用ArrayList中的方法去改造一下。
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
    // replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

這個構造方法不常用,舉個例子就能明白什麼意思

舉個例子: Strudent exends Person , ArrayList、 Person這裏就是泛型 , 我還有一個Collection、 由於這個Student繼承了Person,那麼根據這個構造方法,我就可以把這個Collection轉換爲ArrayList , 這就是這個構造方法的作用 。

【總結】ArrayList的構造方法就做一件事情,就是初始化一下儲存數據的容器,其實本質上就是一個數 組,在其中就叫elementData。

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