ArrayList , Vector 源碼理解
阿新 • • 發佈:2017-09-11
全局變量 res truct all cit ont ted 最小 nbsp
ArrayList 的一些認識:
- 非線程安全的動態數組(Array升級版),支持動態擴容
- 實現 List 接口、底層使用數組保存所有元素,其操作基本上是對數組的操作,允許null值
- 實現了 RandmoAccess 接口,提供了隨機訪問功能
- 線程安全可見Vector,實時同步
- 適用於訪問頻繁場景,頻繁插入或刪除場景請選用linkedList
■ 類定義
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 繼承 AbstractList,實現了 List,它是一個數組隊列,提供了相關的添加、刪除、修改、遍歷等功能
- 實現 RandmoAccess 接口,實現快速隨機訪問:通過元素的序號快速獲取元素對象
- 實現 Cloneable 接口,重寫 clone(),能被克隆(淺拷貝)
- 實現 java.io.Serializable 接口,支持序列化
■ 全局變量
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when the first element is added. * ArrayList底層實現為動態數組; 對象在存儲時不需要維持,java的serialzation提供了持久化
* 機制,我們不想此對象被序列化,所以使用 transient*/ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * 數組長度 :註意區分長度(當前數組已有的元素數量)和容量(當前數組可以擁有的元素數量)的概念 * @serial */ private int size; /** * The maximum size of array to allocate.Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in OutOfMemoryError: * Requested array size exceeds VM limit * 數組所能允許的最大長度;如果超出就會報`內存溢出異常` -- 可怕後果就是宕機*/ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
■ 構造器
/** * 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 */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * Constructs an empty list with an initial capacity of ten. * 默認容量為10 */ public ArrayList() { this(10); } /** * Constructs a list containing the elements of the specified collection, * in the order they are returned by the collection‘s iterator. * 接受一個Collection對象直接轉換為ArrayList * @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();//獲取底層動態數組 size = elementData.length;//獲取底層動態數組的長度 // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }
■主要方法
- add()
/** * Appends the specified element to the end of this list. * 使用尾插入法,新增元素插入到數組末尾 * 由於錯誤檢測機制使用的是拋異常,所以直接返回true * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { //調整容量,修改elementData數組的指向; 當數組長度加1超過原容量時,會自動擴容 ensureCapacityInternal(size + 1); // Increments modCount!! add屬於結構性修改 elementData[size++] = e;//尾部插入,長度+1 return true; } /** * Inserts the specified element at the specified position in this list. * Shifts the element currently at that position (if any) and any subsequent elements to * the right (adds one to their indices). * 支持插入一個新元素到指定下標 * 該操作會造成該下標之後的元素全部後移(使用時請慎重,避免數組長度過大) * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { //下標邊界校驗,不符合規則 拋出 `IndexOutOfBoundsException` rangeCheckForAdd(index); //調整容量,修改elementData數組的指向; 當數組長度加1超過原容量時,會自動擴容 ensureCapacityInternal(size + 1); // Increments modCount!! //註意是在原數組上進行位移操作,下標為 index+1 的元素統一往後移動一位 System.arraycopy(elementData, index, elementData, index + 1,size - index); elementData[index] = element;//當前下標賦值 size++;//數組長度+1 }
-
不推薦頻繁插入或刪除場景的原因在於其執行add或者remove方法時會調用非常耗時的System.arraycopy方法
頻繁插入或刪除場景請選用LinkedList
- set()
/** * Replaces the element at the specified position in this list with * the specified element. * * @param index index of the element to replace * @param element element to be stored at the specified position * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { rangeCheck(index); //檢測插入的位置是否越界 E oldValue = elementData(index); elementData[index] = element; return oldValue; }
- get()
/** * Returns the element at the specified position in this list. * 返回指定下標的元素 * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { rangeCheck(index);//下標邊界校驗 return elementData(index);//直接調用數組的下標方法 } /** * 數組訪問方法 */ @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; }
- remove()
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their indices). * * 移除指定下標元素,同時大於該下標的所有數組元素統一左移一位 * * @param index the index of the element to be removed * @return the element that was removed from the list 返回原數組元素 * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index);//下標邊界校驗 E oldValue = elementData(index);//獲取當前坐標元素 fastRemove(int index);//這裏我修改了一下源碼,改成直接用fastRemove方法,邏輯不變 return oldValue;//返回原數組元素 } /** * Removes the first occurrence of the specified element from this list,if it is present. * If the list does not contain the element, it is unchanged. * More formally, removes the element with the lowest index <tt>i</tt> such that * <tt>(o==null?get(i)==null:o.equals(get(i)))</tt> (if such an element exists). * Returns <tt>true</tt> if this list contained the specified element * (or equivalently, if this list changed as a result of the call). * 直接移除某個元素: * 當該元素不存在,不會發生任何變化 * 當該元素存在且成功移除時,返回true,否則false * 當有重復元素時,只刪除第一次出現的同名元素 : * 例如只移除第一次出現的null(即下標最小時出現的null) * @param o element to be removed from this list, if present * @return <tt>true</tt> if this list contained the specified element */ public boolean remove(Object o) { //按元素移除時都需要按順序遍歷找到該值,當數組長度過長時,相當耗時 if (o == null) {//ArrayList允許null,需要額外進行null的處理(只處理第一次出現的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; }
- fastRemove()
/* * Private remove method that skips bounds checking and does not return the value removed. * 私有方法,除去下標邊界校驗以及不返回移除操作的結果 */ private void fastRemove(int index) { modCount++;//remove操作屬於結構性改動,modCount計數+1 int numMoved = size - index - 1;//需要左移的長度 if (numMoved > 0) //大於該下標的所有數組元素統一左移一位 System.arraycopy(elementData, index+1, elementData, index,numMoved); elementData[--size] = null; // Let gc do its work 長度-1,同時加快gc }
■遍歷、排序
/** * Created by meizi on 2017/7/31. * List<數據類型> 排序、遍歷 * */ public class ListSortTest { public static void main(String[] args) { List<Integer> nums = new ArrayList<Integer>(); nums.add(3); nums.add(5); nums.add(1); nums.add(0); // 遍歷及刪除的操作 since 1.7 Iterator<Integer> iterator = nums.iterator(); while (iterator.hasNext()) { Integer num = iterator.next(); if(num.equals(5)) { System.out.println(num); iterator.remove(); //可刪除 } } System.out.println(nums); //①工具類進行排序 Collections.sort(nums); //底層為數組對象的排序,再通過ListIterator進行遍歷比較,取替 System.out.println(nums); //②自定義排序方式 nums.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { if(o1 > o2) { return 1; } else if (o1 < o2) { return -1; } else { return 0; } } }); System.out.println(nums); //遍歷 since 1.8 // TODO: 2017/7/31 /*Iterator<Integer> iterator = nums.iterator(); iterator.forEachRemaining(obj -> System.out.print(obj + ","));*/ //使用了lambda } }
■ 關於Vector的一些理解:
- 矢量隊列,作用等效於ArrayList,線程安全
- 官方不推薦使用該類,非線程安全推薦 ArrayList,線程安全推薦 CopyOnWriteList
- 區別於arraylist, 所有方法都是 synchronized 修飾的,所以是線程安全
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
- 繼承 AbstractList,實現了 List,它是一個數組隊列,提供了相關的添加、刪除、修改、遍歷等功能
- 實現 RandmoAccess 接口,實現快速隨機訪問:通過元素的序號快速獲取元素對象
- 實現 Cloneable 接口,重寫 clone(),能被克隆(淺拷貝)
- 實現 java.io.Serializable 接口,支持序列化
- 全局變量
/* 底層數據結構為動態數組 */ protected Object[] elementData; /* 數組的長度 == arraylist.size() */ protected int elementCount; /* vector增量值 (擴容時) */ protected int capacityIncrement;
ArrayList , Vector 源碼理解