1. 程式人生 > >java集合類之ArrayList詳解

java集合類之ArrayList詳解

int() 相等 toa isempty ont ati urn 影響 輸入

一、ArrayList源碼分析

1、全局變量

(1)默認容量(主要是通過無參構造函數創建ArrayList時第一次add執行擴容操作時指定的elementData的數組容量為10)

 private static final int DEFAULT_CAPACITY = 10;

(2)空的對象數組(當通過指定容量的構造方法創建ArrayList時指定給elementData,用於區分DEFAULTCAPACITY_EMPTY_ELEMENTDATA,比如說在得到最小擴容容量時判斷elementData是通過哪個構造函數指定的哪個數組)

 private static final Object[] EMPTY_ELEMENTDATA = {};

(3)默認的空數組(用於區分EMPTY_ELEMENTDATA,主要針對構造函數)

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

(4)存放數據的數組的緩存變量,不可序列化

 transient Object[] elementData;

(5)元素數量(註意區分length,length是數組elementData的容量,而size是元素數量)

 private int size;

2、構造函數

(1)帶有容量initialCapacity的構造方法

 public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

(2)不帶參數的構造方法

 public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

(3)帶參數Collection的構造方法

 public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    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;
    }
}

參數c為一個Collection,Collection的實現類大概有以下幾種常用類型:

  • List:元素可以重復的容器
  • Set: 元素不可重復的容器
  • Queue:結構是一個隊列,先進先出
    這個構造方法的意思是,將一個Collection實現類的對象轉換為一個ArrayList,但是c容器裝的內容必須為ArrayList裝的內容的子類。例如,將一個裝了String內容的HashSet轉換為裝了String內容的ArrayList,使得ArrayList的大小和值數組都是HashSet的大小和值數組。具體實現如下代碼,首先調用c(Collection的具體實現類)的toArray方法,具體大家可以看各個實現類的toArray方法,但是大概意思都是將c容器轉換為object類型的數組,因為它們的返回值都是object[]。之於下面的兩個判斷是當得到的elementData的類名不是Object類名的時候或者是長度為0的時候才會執行。

3、方法

(1)trimToSize()

 public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

說明

將ArrayList的容量設置為當前size的大小。首先需要明確一個概念,ArrayList的size就是ArrayList的元素個數,length是ArrayList申請的內容空間長度。ArrayList每次都會預申請多一點空間,以便添加元素的時候不需要每次都進行擴容操作,例如我們的元素個數是10個,它申請的內存空間必定會大於10,即length>size,而這個方法就是把ArrayList的內存空間設置為size,去除沒有用到的null值空間。這也就是我們為什麽每次在獲取數據長度是都是調用list.size()而不是list.length()。(list不可調用length,因為不存在變量length)

源碼詳解

首先modCount是從類 java.util.AbstractList 繼承的字段,這個字段主要是為了防止在多線程操作的情況下,List發生結構性的變化,什麽意思呢?就是防止一個線程正在叠代,另外一個線程進行對List進行remove操作,這樣當我們叠代到最後一個元素時,很明顯此時List的最後一個元素為空,那麽這時modCount就會告訴叠代器,讓其拋出異常 ConcurrentModificationException。
如果沒有這一個變量,那麽系統肯定會報異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應該出現的(這些運行時錯誤都是使用者的邏輯錯誤導致的,我們的JDK那麽高端,不會出現使用錯誤,我們只拋出使用者造成的錯誤,而這個錯誤是設計者應該考慮的),為了避免出現這樣的異常,定義了檢查。

(2)size()

 public int size() {
    return size;
}

說明:返回ArrayList的大小
源碼解釋:直接返回size

(3)isEmpty()

 public boolean isEmpty() {
    return size == 0;
}

說明:返回ArrayList是否為空
解釋說明:直接返回判斷size==0

(4)indexOf(Object o)

 public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

說明

對象o在ArrayList中的下標位置,如果存在返回位置i,不存在返回-1
源碼解釋

遍歷ArrayList的大小,比較o和容器內的元素,若相等,則返回位置i,若遍歷完都不相等,返回-1

(5)contails(Object o)

 public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

說明

是否包含對象o

源碼解釋

調用indexOf()方法得到下標,存在則下標>=0,不存在為-1,即只要比較下標和0的大小即可

(6)lastIndexOf(Object o)

 public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

說明

返回容器內出現o的最後一個位置

源碼解釋

從後向前遍歷,得到第一個出現對象o的位置,不存在則返回-1

(7)clone()

 public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

說明:返回此ArrayList實例的淺表副本

(8)toArray()

 public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

說明

ArrayList實例轉換為Array數組

源碼解釋

直接調用Arrays類的copyOf

(9)toArray(T[] a)

 public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

說明

將ArrayList裏面的元素賦值到一個數組中去

源碼解釋

如果a的長度小於ArrayList的長度,直接調用Arrays類的copyOf,返回一個比a數組長度要大的新數組,裏面元素就是ArrayList裏面的元素;如果a的長度比ArrayList的長度大,那麽就調用System.arraycopy,將ArrayList的elementData數組賦值到a數組,然後把a數組的size位置賦值為空

(10)rangeCheck(int index)

 private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

說明

測試index是否越界

源碼解釋

如果index超出ArrayList的數組長度,就會拋出IndexOutOfBoundsException異常,註意 訪問控制修飾符Private只能在同一類中使用

(11)rangeCheckForAdd(int index)

 private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

說明:測試index是否越界(add、addall操作時)

(12)get(int index)

 public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

說明:獲取index位置的元素

源碼解釋

先檢查是否越界,然後返回ArrayList的elementData數組index位置的元素

(13)set(int index,E element)

 public E set(int index, E element) {
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

說明:設置index位置的元素值為element,返回該位置之前的值

(14)ensureCapacityInternal(int minCapacity)

     private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    //獲取默認的容量和傳入參數的較大值
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

說明:得到最小擴容量

(15)ensureExplicitCapacity(int minCapacity)

 private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //如果最小需要空間比ElementData的內存空間要大,則需要擴容
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

說明:判斷是否需要擴容

(16)grow(int minCapacity)

 // MAX_VALUE為231-1,MAX_ARRAY_SIZE 就是獲取Java中int的最大限制,以防止越界    
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  
private void grow(int minCapacity) {  
// 獲取到ArrayList中elementData數組的內存空間長度  
int oldCapacity = elementData.length;  
// 擴容至原來的1.5倍  
int newCapacity = oldCapacity + (oldCapacity >> 1);  
// 再判斷一下新數組的容量夠不夠,夠了就直接使用這個長度創建新數組,   
// 不夠就將數組長度設置為需要的長度  
if (newCapacity - minCapacity < 0)  
    newCapacity = minCapacity;  
// 判斷有沒超過最大限制  
if (newCapacity - MAX_ARRAY_SIZE > 0)  
    newCapacity = hugeCapacity(minCapacity);  
// 調用Arrays.copyOf方法將elementData數組指向新的內存空間時newCapacity的連續空間  
// 並將elementData的數據復制到新的內存空間  
elementData = Arrays.copyOf(elementData, newCapacity);  

}

說明:幫助ArrayList動態擴容的核心方法

(17)hugeCapacity(int minCapacity)

 private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

說明:由grow(int minCapacity)調用

(18)add(E e)

 public boolean add(E e) {  
 // 擴容  
    ensureCapacityInternal(size + 1);    
// 將e賦值給elementData的size+1的位置。  
    elementData[size++] = e;  
    return true;  
}  

說明:添加元素e

(19)add(int index,E element)

 public void add(int index, E element) {  
// 判斷index是否越界    
    rangeCheckForAdd(index);  
 // 擴容  
    ensureCapacityInternal(size + 1);    
 // 將elementData從index位置開始,復制到elementData的index+1開始的連續空間  
    System.arraycopy(elementData, index, elementData, index + 1,  
                 size - index);  
 // 在elementData的index位置賦值element  
    elementData[index] = element;  
 // ArrayList的大小加一    
    size++;  

}

說明:在ArrayList的index位置,添加元素element

(20)remove(int index)

 public E remove(int index) {  
 // 判斷是否越界    
    rangeCheck(index);  
    modCount++;  
 // 讀取舊值    
    E oldValue = elementData(index);  
 // 獲取index位置開始到最後一個位置的個數  
    int numMoved = size - index - 1;  
    if (numMoved > 0)  
     // 將elementData數組index+1位置開始拷貝到elementData從index開始的空間  
    System.arraycopy(elementData, index+1, elementData, index,  
                     numMoved);  
 // 使size-1 ,設置elementData的size位置為空,讓GC來清理內存空間  
    elementData[--size] = null; // clear to let GC do its work  
    return oldValue;  
}  

說明:在ArrayList移除index位置的元素

(21)remove(Object o)

 public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

說明:在ArrayList中移除對象為o的元素,跟indexOf方法的思想基本一致

(22)fastRemove(int index)

 private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

說明:被remove(Object o)調用

(23)clear()

 public void clear() {
    modCount++;
    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    size = 0;
}

說明

設置全部元素為null值,並設置size為0

源碼解釋

可見clear操作並不是從空間內刪除,只是設置為null值,等待垃圾回收機制來回收而已,把size設置為0,以便我們不會瀏覽到null值的內存空間

(24)addAll(Collection<? extend E> c)

 public boolean addAll(Collection<? extends E> c) {
 // 將c轉換為數組a  
    Object[] a = c.toArray();  
 // 獲取a占的內存空間長度賦值給numNew  
    int numNew = a.length;  
 // 擴容至size + numNew  
    ensureCapacityInternal(size + numNew);  // Increments modCount  
 // 將a的第0位開始拷貝至elementData的size位開始,拷貝長度為numNew  
    System.arraycopy(a, 0, elementData, size, numNew);  
 // 將size增加numNew    
    size += numNew;  
 // 如果c為空,返回false,c不為空,返回true  
    return numNew != 0;  

}

說明:將Collection c的全部元素添加到ArrayList中

(25)addAll(int index,Collection<? extend E> c)

 public boolean addAll(int index, Collection<? extends E> c) {  
 // 判斷index大於size或者是小於0,如果是,則拋出IndexOutOfBoundsException異常  
    rangeCheckForAdd(index);  
 // 將c轉換為數組a  
    Object[] a = c.toArray();  
    int numNew = a.length;  
 // 擴容至size + numNew  
    ensureCapacityInternal(size + numNew);  // Increments modCount  
  // 獲取需要添加的個數  
    int numMoved = size - index;  
    if (numMoved > 0)  
    System.arraycopy(elementData, index, elementData, index + numNew,  
                     numMoved);  
    System.arraycopy(a, 0, elementData, index, numNew);  
    size += numNew;  
    return numNew != 0;  

}

說明:從第index位開始,將c全部拷貝到ArrayList

(26)removeRange(int fromIndex,int toIndex)

 protected void removeRange(int fromIndex, int toIndex) {
    modCount++;
    int numMoved = size - toIndex;
    System.arraycopy(elementData, toIndex, elementData, fromIndex,
                     numMoved);
    // clear to let GC do its work
    int newSize = size - (toIndex-fromIndex);
    for (int i = newSize; i < size; i++) {
        elementData[i] = null;
    }
    size = newSize;
}

說明:Removes from this list all of the elements whose index is between
{@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
可以選擇繼承ArrayList編寫自己的List類來調用這個方法
(Protected訪問控制修飾符)

(27)batchRemove(Collection<?> c, boolean complement)

 private boolean batchRemove(Collection<?> c, boolean complement) {  
    final Object[] elementData = this.elementData;  
 // 定義一個w,一個r,兩個同時右移     
    int r = 0, w = 0;  
    boolean modified = false;  
    try {  
     // r先右移  
        for (; r < size; r++)  
          // 如果c中不包含elementData[r]這個元素  
            if (c.contains(elementData[r]) == complement)  
              // 則直接將r位置的元素賦值給w位置的元素,w自增  
            elementData[w++] = elementData[r];  
        } finally {  
    // 防止拋出異常導致上面r的右移過程沒完成  
        if (r != size) {  
          // 將r未右移完成的位置的元素賦值給w右邊位置的元素  
            System.arraycopy(elementData, r,  
                         elementData, w,  
                         size - r);  
          // 修改w值增加size-r  
            w += size - r;  
        }  
        if (w != size) {  
        // 如果有被覆蓋掉的元素,則將w後面的元素都賦值為null  
            for (int i = w; i < size; i++)  
                elementData[i] = null;  
            modCount += size - w;  
          // 修改size為w  
            size = w;  
            modified = true;  
        }  
    }  
    return modified;    
}  

說明:根據complement值,將ArrayList中包含c中元素的元素刪除或者保留,被removeAll(collection<?> c)和retailAll(collection<?> c)兩個方法調用

(28)removeAll(collection<?> c)

 public boolean removeAll(Collection<?> c) {  
 // 如果c為空,則拋出空指針異常  
    Objects.requireNonNull(c);  
 // 調用batchRemove移除c中的元素  
    return batchRemove(c, false);  
}  

說明:ArrayList移除c中的所有元素

(29)retainAll(collection<?> c)

 public boolean retainAll(Collection<?> c) {  
Objects.requireNonNull(c);  
 // 調用batchRemove保留c中的元素  
return batchRemove(c, true);  
} 

說明:和removeAll相反,僅保留c中所有的元素

(30)iterator()

 public Iterator<E> iterator() {
    return new Itr();
}

說明:返回一個Iterator對象,Itr為ArrayList的一個內部類,其實現了Iterator接口

(31)listIterator()

 public ListIterator<E> listIterator() {
    return new ListItr(0);
}

說明:返回一個ListIterator對象,ListItr為ArrayList的一個內部類,其實現了ListIterator接口

(32)listIterator(int index)

 public ListIterator<E> listIterator(int index) {
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index);
    return new ListItr(index);
}

說明:返回一個從index開始的ListIterator對象

(33)subList(int fromIndex,int toIndex)

 public List<E> subList(int fromIndex, int toIndex) {  
 // 檢查異常  
    subListRangeCheck(fromIndex, toIndex, size);  
 // 調用SubList類的構造方法  
    return new SubList(this, 0, fromIndex, toIndex);  
}  

說明:根據兩個參數,獲取到一個子序列

(34)subListRangeCheck(int fromIndex, int toIndex, int size)

 static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < 0)
        throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > size)
        throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
        throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                           ") > toIndex(" + toIndex + ")");
}

說明:根據輸入的不合理參數拋出異常

(35)sort(Comparator<? super E> c)

 public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

說明:將列表中的值排序使用方法如下(匿名內部類):

 arrayList.sort(new Comparator<E>() {
        @Override
        public int compare(E o1, E o2) 
            return o1.compareTo(o2);//Integer使用
        }
    });

(36)writeObject(java.io.ObjectOutputStream s)

 private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();
    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);
    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

(37)readObject(java.io.ObjectInputStream s)

 private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;
    // Read in size, and any hidden stuff
    s.defaultReadObject();
    // Read in capacity
    s.readInt(); // ignored
    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);
        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

(42)outOfBoundsMsg(int index)

 private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size;
}

4、內部類

ArrayList有四個內部類,

Itr

其中的Itr是實現了Iterator接口,同時重寫了裏面的hasNext(),next(),remove()等方法;

ListItr

其中的ListItr繼承Itr,實現了ListIterator接口,同時重寫了hasPrevious(),nextIndex(),
previousIndex(),previous(),set(E e),add(E e)等方法,所以這也可以看出了Iterator和ListIterator的區別,就是ListIterator在Iterator的基礎上增加了添加對象,修改對象,逆向遍歷等方法,這些是Iterator不能實現的。

SubList

其中的SubList繼承AbstractList,實現了RandmAccess接口,得到子序列類內部實現了對子序列的增刪改查等方法,但它同時也充分利用了內部類的優點,就是共享ArrayList的全局變量,例如檢查器變量modCount,數組elementData等,所以SubList進行的增刪改查操作都是對ArrayList的數組進行的,並沒有創建新的數組

ArrayListSpliterator

並行遍歷,區分於Iterator的順序遍歷

該方法會把當前元素劃分一部分出去創建一個新的Spliterator作為返回,兩個Spliterator變會並行執行,如果元素個數小到無法劃分則返回null

二、ArrayList的動態擴容機制

根據上面的ArrayList源碼可知,ArrayList分三個構造函數,分別對應不同的擴容機制

1、無參構造

初始化的時候,elementData的數組長度為0,現在添加數據

 public boolean add(E e) {
    //確保內部容量(通過判斷,如果夠則不進行操作;容量不夠就擴容來確保內部容量)
    ensureCapacityInternal(size + 1);  // ①Increments modCount!!
    elementData[size++] = e;//②
    return true;
}

得到最小擴容量(最小需要容量)

private void ensureCapacityInternal(int minCapacity) {
  //如果實際存儲數組 是空數組,則最小需要容量就是默認容量
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

如果數組elementData的長度小於最小需要的容量(minCapacity)就擴容

   private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //如果數組(elementData)的長度小於最小需要的容量(minCapacity)就擴容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

擴容的核心方法

/*
*增加容量,以確保它至少能容納
*由最小容量參數指定的元素數。
* @param mincapacity所需的最小容量
*/
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //>>位運算,右移動一位。 整體相當於newCapacity =oldCapacity + 0.5 * oldCapacity  

    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;

    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 最重要的復制元素方法
    elementData = Arrays.copyOf(elementData, newCapacity);
}

總結:

ArrayList在沒有指定initialCapacity時就是會使用延遲分配數組空間,當第一次插入元素時才分配默認10個對象空間,下一次需要擴容的時候就會按照1.5倍增長(位運算)

關於Arrays.copyOf(T[] original, int newLength)

    public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}

/**
    * @Description 復制指定的數組, 如有必要用 null 截取或填充,以使副本具有指定的長度
    * 對於所有在原數組和副本中都有效的索引,這兩個數組相同索引處將包含相同的值
    * 對於在副本中有效而在原數組無效的所有索引,副本將填充 null,當且僅當指定長度大於原數組的長度時,這些索引存在
    * 返回的數組屬於 newType 類

    * @param original 要復制的數組
    * @param 副本的長度
    * @param 副本的類
    * 
    * @return 原數組的副本,截取或用 null 填充以獲得指定的長度
    * @throws NegativeArraySizeException 如果 newLength 為負
    * @throws NullPointerException 如果 original 為 null
    * @throws ArrayStoreException 如果從 original 中復制的元素不屬於存儲在 newType 類數組中的運行時類型

    * @since 1.6
*/
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

參數說明: 
src:源對象 
srcPos:源數組中的起始位置 
dest:目標數組對象 
destPos:目標數據中的起始位置 
length:要拷貝的數組元素的數量
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);
                                    

從代碼可知,數組拷貝時調用的是本地方法 System.arraycopy() ;
Arrays.copyOf()方法返回的數組是新的數組對象,原數組對象仍是原數組對象,不變,該拷貝不會影響原來的數組。

2、帶初始容量的構造函數

分兩種情況:

一種是指定容量為0,指定為0的話,添加第一個元素擴容後,elementData的容量為1,繼續添加元素,又需要擴容,容量變為1.5倍,所以不推薦指定為0

第二種情況就是指定不為0,然後就直接在構造函數指定了數組容量,然後當所需的最小容量大於數組容量時就會擴容,擴容機制跟上述一樣,

三、ArrayList與LinkedList的區別

  • ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構
  • 對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指針
  • 對於新增和刪除操作add和remove,LinkedList比較占優勢,因為ArrayList要移動數據

四、ListIterator與Iterator的詳解

在使用Java集合的時候,都需要使用Iterator。但是java集合中還有一個叠代器ListIterator,在使用List、ArrayList、LinkedList和Vector的時候可以使用。

Iterator叠代器包含的方法

hasNext():如果叠代器指向位置後面還有元素,則返回 true,否則返回false

next():返回集合中Iterator指向位置後面的元素

remove():刪除集合中Iterator指向位置後面的元素

ListIterator叠代器包含的方法

add(E e): 將指定的元素插入列表,插入位置為叠代器當前位置之前

hasNext():以正向遍歷列表時,如果列表叠代器後面還有元素,則返回 true,否則返回false

hasPrevious():如果以逆向遍歷列表,列表叠代器前面還有元素,則返回 true,否則返回false

next():返回列表中ListIterator指向位置後面的元素

nextIndex():返回列表中ListIterator所需位置後面元素的索引

previous():返回列表中ListIterator指向位置前面的元素

previousIndex():返回列表中ListIterator所需位置前面元素的索引

remove():從列表中刪除next()或previous()返回的最後一個元素(有點拗口,意思就是對叠代器使用hasNext()方法時,刪除ListIterator指向位置後面的元素;當對叠代器使用hasPrevious()方法時,刪除ListIterator指向位置前面的元素)

set(E e):從列表中將next()或previous()返回的最後一個元素返回的最後一個元素更改為指定元素e

主要區別

  • 使用範圍不同,Iterator可以應用於所有的集合,Set、List和Map和這些集合的子類型。而ListIterator只能用於List及其子類型。

  • ListIterator有add方法,可以向List中添加對象,而Iterator不能。

  • ListIterator和Iterator都有hasNext()和next()方法,可以實現順序向後遍歷,但是ListIterator有hasPrevious()和previous()方法,可以實現逆向(順序向前)遍歷。Iterator不可以。

  • ListIterator可以定位當前索引的位置,nextIndex()和previousIndex()可以實現。Iterator沒有此功能。

  • 都可實現刪除操作,但是ListIterator可以實現對象的修改,set()方法可以實現。Iterator僅能遍歷,不能修改。

java集合類之ArrayList詳解