ArrayList源碼分析

ArrayList源碼分析

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

ArrayList繼承自AbstractList,實現了List、RandomAccess、Cloneable、Serializable接口java

方法:

1、構造方法

1.無參構造數組

/**
     * 第一種、調用ArrayList(10)默認初始化一個大小爲10的Object數組
     (DEFAULTCAPACITY_EMPTY_ELEMENTDATA=10)
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • ArrayList():構造一個廚師容量爲10的空列表

2.有參構造安全

/**
     *第二種
     */
    public ArrayList(int initialCapacity) {
        //若是用戶初始化大小小於0拋異常
		//不然新建一個用戶初始值大小的Object數組
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  • ArrayList( int initialCapcity ):構造一個具備初始容量值的空列表
/**
     * 第三種、將容器數組化處理並將這個數組值賦給Object數組
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            //當c.toArray返回的不是Object類型的數組時,進行下面轉化
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 用空數組替換
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • ArrayList(Collection<?extend E> c):構造一個包含指定元素的列表

2、增刪改查操做

1.增長元素

//第一步:
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  
        elementData[size++] = e;
        return true;
    }
//第二步:
 private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
//第三步:
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 若是添加元素後大於當前數組的長度,則進行擴容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
//第四步:(擴容)
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //將數組的長度增長原來數組的一半
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若是擴充一半後仍然不夠,則newCapacity=minCapacity;(minCapacity實際元素的個數)
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
//第一步:
public void add(int index, E element) {
        rangeCheckForAdd(index);
		//檢查index的值是否在0到size之間,能夠爲size。
        ensureCapacityInternal(size + 1);  //看elementData的長度是否足夠,不夠擴容
    	//將elementData從index開始後面的元素日後移一位
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
//第二步:(多了判斷index是否超出範圍)
 private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
//第三步:
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
//第四步:(判斷是否須要擴容)
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
     	// 若是添加元素後大於當前數組的長度,則進行擴容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
//第五步:(擴容)
   private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
       //將數組的長度增長原來數組的一半
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
       //若是擴充一半後仍然不夠,則newCapacity=minCapacity;(minCapacity實際元素的個數)
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
  • add(E e):添加一個元素到列表的末尾。
  • add( int index, E element ) :在指定的位置添加元素
  • addAll( Collection<? extends E> c ):添加一個集合到元素的末尾.以上返回類型是boolean
  • ensureCapcity(int minCapcity):確保列表中含有minCapcity的最小容

2.刪除元素

public E remove(int index) {
    	//第一步:若是index>=size拋出異常
        rangeCheck(index);
        modCount++;
    	//第二步:獲取刪除元素的值
        E oldValue = elementData(index);
		//第三步:將index後面全部元素往前移一位
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null;
		//第四步:返回要刪除的元素
        return oldValue;
    }
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;
    }
  • remove(Object o):刪除列表中第一個出現O的元素
  • removeAll(Collection<?> c):刪除列表中包含C的全部元素
  • removeIf(Predictcate<? super E> filter):刪除列表中給定謂詞的全部元素
  • removeRange( int from,int to ):刪除從from到to的全部元素
  • clear():清除全部的元素。返回類型爲void

3.更改元素

//第一步:
public E set(int index, E element) {
    	//檢查index是否小於size,若是不是拋異常
        rangeCheck(index);
        E oldValue = elementData(index);
    	//覆蓋ArrayList中index上的元素
        elementData[index] = element;
    	//返回被覆蓋的元素
        return oldValue;
}
//第二步:
private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//第一步:
public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
//第二步:
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 + ")");
    }
//1)修改次數加1
//2)強elementData中空餘的空間(包括null值)去除,
//例如:數組長度爲10,其中只有前三個元素有值,其餘爲空,那麼調用該方法以後,數組長度變爲3
public void trimToSize() {
    	//修改次數加1
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)? 
                EMPTY_ELEMENTDATA: Arrays.copyOf(elementData, size);
        }
    }
public Object[] toArray() {return Arrays.copyOf(elementData, size);}
//第一種方式(最經常使用)
Integer[] integer=arrayList.toArray(new Integer[0]);
//第二種方式(容易理解)
Integer[] integer=new Integer[arrayList.size()];
arrayList.toArray(integer);
  • retainAll( Collection<?> c ):僅僅保留列表中和C相同的元素,至關於&運算
  • set(int index,E element):用element替換index位置上的元素。
  • size():返回此列表的元素數
  • sort(Comparator<? super E> c):按照指定的排序規則排序
  • subList( int from , int to ):返回從from到to之間的列表
  • toArray():將列表轉化爲數組
  • trimToSize( ):修改當前實例的容量是列表的當前大小。

4.查元素

contains()多線程

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
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;
    }
  • contains(Object o):若是包含元素o,則返回爲true
  • get(int index):返回指定索引的元素
  • indexOf( Object o ):返回此列表中指定元素的第一次出現的索引,若是列表不包含此元素,返回-1
  • lastindexOf( Object o ):返回此列表中指定元素的最後一次出現的索引,若是列表不包含此元素,返回-1
  • isEmpty():若是列表爲空,返回true.
  • iterator():返回列表中元素的迭代器
  • listIterator():返回列表的列表迭代器(按適當的順序)
  • listIterator(int index):從適當的位置返回列表的列表迭代器(按照正確的順序)

5.遍歷元素

public class Test01 {
    public static void main(String[] args) {
        List<String> list1=new ArrayList<>();
        list1.add("A");
        list1.add("B");
        list1.add("C");
        
        //第一種遍歷方式:迭代器
        Iterator<String> iterator=list1.iterator();
        while (iterator.hasNext()){
            String result=iterator.next();
            System.out.println(result);
        }
        
        //第二種遍歷方式:經過下標遍歷
        for (int i = 0; i < list1.size(); i++) {
            String result=list1.get(0);
            System.out.println(result);
        }
        //第三種遍歷方式:for-each
        for (String a:list1) {
            System.out.println(a);
        }
    }
}

第二種遍歷的效率是最高的。dom

三種方式時間差對比:源碼分析

package com.woniu.chapter23;

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

/**
 * @Author: Aweicy
 * @Date: 2020/4/110:33
 */
public class Test01 {
    public static void main(String[] args) {
        List<String> list1=new ArrayList<>();
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("A");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        list1.add("B");
        list1.add("C");
        Long time1=System.currentTimeMillis();
        //第一種遍歷方式:迭代器
        Iterator<String> iterator=list1.iterator();
        while (iterator.hasNext()){
            String result=iterator.next();
            System.out.println(result);
        }
        Long time2=System.currentTimeMillis();
        System.out.println(time2-time1);
        Long time3=System.currentTimeMillis();
        //第二種遍歷方式:經過下標遍歷
        for (int i = 0; i < list1.size(); i++) {
            String result=list1.get(0);
            System.out.println(result);
        }
        Long time4=System.currentTimeMillis();
        System.out.println(time4-time3);
        Long time5=System.currentTimeMillis();
        //第三種遍歷方式:for-each
        for (String a:list1) {
            System.out.println(a);
        }
        Long time6=System.currentTimeMillis();
        System.out.println(time6-time5);
    }
}
  • 5毫秒
  • 3毫秒
  • 5毫秒

3、與LinkList、Vector對比區別

分析得出下面結論:性能

  • ArrayList 本質上是一個可改變大小的數組.當元素加入時,其大小將會動態地增加.內部的元素能夠直接經過get與set方法進行訪問.元素順序存儲 ,隨機訪問很快,刪除非頭尾元素慢,新增元素慢並且費資源 ,較適用於無頻繁增刪的狀況 ,比數組效率低,若是不是須要可變數組,可考慮使用數組 ,非線程安全.
  • LinkedList 是一個雙鏈表,在添加和刪除元素時具備比ArrayList更好的性能.但在get與set方面弱於ArrayList. 適用於 :沒有大規模的隨機讀取,有大量的增長/刪除操做.隨機訪問很慢,增刪操做很快,不耗費多餘資源 ,容許null元素,非線程安全.
  • Vector (相似於ArrayList)但其是同步的,開銷就比ArrayList要大。若是你的程序自己是線程安全的,那麼使用ArrayList是更好的選擇。 Vector和ArrayList在更多元素添加進來時會請求更大的空間。Vector每次請求其大小的雙倍空間,而ArrayList每次對size增加50%.

4、總結

ArrayList整體來講比較簡單,不過ArrayList還有如下一些特色:this

  • ArrayList本身實現了序列化和反序列化的方法,由於它本身實現了private void writeObject(java.io.ObjectOutputStream s)、private void readObject(java.io.ObjectInputStream s) 方法
  • ArrayList基於數組方式實現,無容量的限制(會擴容)
  • 添加元素時可能要擴容(因此最好預判一下),刪除元素時不會減小容量(若但願減小容量,trimToSize()),刪除元素時,將刪除掉的位置元素置爲null,下次gc就會回收這些元素所佔的內存空間。
  • 線程不安全,會出現fall-fail。
  • add(int index, E element):添加元素到數組中指定位置的時候,須要將該位置及其後邊全部的元素都整塊向後複製一位
  • get(int index):獲取指定位置上的元素時,能夠經過索引直接獲取(O(1)
  • remove(Object o)須要遍歷數組
  • remove(int index)不須要遍歷數組,只需判斷index是否符合條件便可,效率比remove(Object o)高
  • contains(E)須要遍歷數組
  • 使用iterator遍歷可能會引起多線程異常
相關文章
相關標籤/搜索