Java 的 ArrayList 的底層資料結構
1. 資料結構--ArrayList原始碼摘要
ublic class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 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.
*/
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
}
ArrayList 的底層最重要的兩個屬性:Object 陣列和 size 屬性。
2. ArrayList 的底層陣列的調整
add方法--ArrayList原始碼摘要
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
grow方法--ArrayList原始碼摘要
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 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;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2點結論:
a. ArrayList 是通過將底層 Object 陣列複製的方式(System.arraycopy方法)來處理陣列的增長;
b. 當ArrayList 的容量不足時,其擴充容量的方式:先將容量擴充至當前容量的1.5倍,若還不夠,則將容量擴充至當前需要的數量(grow方法)。
remove 方法--ArrayList原始碼摘要
/**
* 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);
modCount++;
E oldValue = elementData(index);
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
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).
*
* @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) {
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;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
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
}
這也就解釋了 ArrayList 的特點:增加、刪除和移動元素的效率低(陣列複製過程消耗資源較多); 而查詢元素和更新元素的效率高。
3. ArrayList與Vector的區別
1) vector 是執行緒同步的,所以它也是執行緒安全的,而arraylist 是執行緒非同步的,是不安全的。如果不考慮到執行緒的安全因素,一般用 arraylist效率比較高。
2)如果集合中的元素的數目大於目前集合陣列的長度時,vector 增長率為目前陣列長度的100%, 而arraylist 增長率為目前陣列長度的50% .如果在集合中使用資料量比較大的資料,用vector有一定的優勢。
3)如果查詢一個指定位置的資料,vector和arraylist使用的時間是相同的,都是O(1) ,這個時候使用vector和arraylist都可以。
而如果移動一個指定位置的資料花費的時間為O(n-i)n為總長度,這個時候就應該考慮到使用linklist ,因為它移動一個指定位置的資料所花費的時間為0(1),而查詢一個指定位置的資料時花費的時間為0(i)。
相關文章
- ArrayList底層結構和原始碼分析原始碼
- Redis - 底層資料結構Redis資料結構
- Redis(二)--- Redis的底層資料結構Redis資料結構
- 【Mysql】索引底層資料結構MySql索引資料結構
- Redis 概念以及底層資料結構Redis資料結構
- JAVA ArrayList集合底層原始碼分析Java原始碼
- Java資料結構之LinkedList、ArrayList的效率分析Java資料結構
- ArrayList底層的實現原理
- Redis基本資料型別底層資料結構Redis資料型別資料結構
- 深入瞭解Redis底層資料結構Redis資料結構
- Redis底層資料結構——壓縮列表Redis資料結構
- HashMap底層資料結構原始碼解析HashMap資料結構原始碼
- 解析ArrayList的底層實現(上)
- ArrayList集合底層原理
- ArrayList 資料結構分析資料結構
- Redis的ZSet底層資料結構,ZSet型別全面解析Redis資料結構型別
- Redis資料結構SortedSet底層原理詳解Redis資料結構
- 【redis】-- 資料結構及底層編碼篇Redis資料結構
- 深入理解MySQL索引底層資料結構MySql索引資料結構
- Redis - 資料型別對映底層結構Redis資料型別
- ArrayList底層原理淺析
- Redis原始碼分析-底層資料結構盤點Redis原始碼資料結構
- Redis List 底層三種資料結構原理剖析Redis資料結構
- Redis學習筆記(二)redis 底層資料結構Redis筆記資料結構
- 關於資料連結底層
- Redis(一):基本資料型別與底層儲存結構Redis資料型別
- 【資料結構】ArrayList原理及實現資料結構
- 一文讀懂Redis常見物件型別的底層資料結構Redis物件型別資料結構
- HashMap的底層結構、原理、擴容機制HashMap
- Redis系列(一)底層資料結構之簡單動態字串Redis資料結構字串
- ArrayList底層陣列擴容原理 - Java那些事兒專欄陣列Java
- ArrayList 從原始碼角度剖析底層原理原始碼
- jdk1.6ArrayList底層實現JDK
- mysql儲存引擎InnoDB詳解,從底層看清InnoDB資料結構MySql儲存引擎資料結構
- MySQL索引及優化(1)儲存引擎和底層資料結構MySql索引優化儲存引擎資料結構
- 層次結構資料的資料庫儲存和使用資料庫
- 資料結構與集合之(1)ArrayList 與 Arrays資料結構
- Vector底層結構和程式碼解析