一直想記錄自己的學習過程,但始終沒有付出實際行動,說來慚愧
感謝您的關注,持續更新,歡迎留言交流~
前言:
雖然面試我們通常是講ArrayList和數組的區別,但小編覺得,我們有必要去了解一下ArrayList,在我們日常開發上,ArrayList也算得上是一種常用的集合了,接下來就和小編一起來扯下淡吧~
話不多說,直接上源碼,以下源碼基於JDK1.8 讓我們先來看看
ArrayList list = new ArrayList();
list.add("小編是個禿頂的大叔~");
// 默認爲 0
private int size;
/**
* 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) {
// size[0] + 1 當作參數傳入方法
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
接下來我們來看看ensureCapacityInternal()方法
思路:其實就是判斷數組是否初始化,未初始化賦初始值 10
// transient是用來反序列化的
transient Object[] elementData;
// 定義一個空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 默認容量爲 10
private static final int DEFAULT_CAPACITY = 10;
/**
* minCapacity:當前存放值的下標 + 1(size + 1)
*/
private void ensureCapacityInternal(int minCapacity) {
// 判斷elementData是不是默認的空數組
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 取得兩個參數中的最大值:DEFAULT_CAPACITY --> 10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// minCapacity = 10
ensureExplicitCapacity(minCapacity);
}
接下來我們看看ensureExplicitCapacity()方法:
擴容的大致整體思路:
1.判斷這個集合是否達到擴容的標準
2.若擴容之後的長度比當前的容量還小,則擴容的容量 = 當前容量(minCapaccity)
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//modCount是記錄修改次數 與線程安全有關係
// 判斷是否達到擴容的條件: 當前容量 > 數組長度
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// 賦值以前的容量
int oldCapacity = elementData.length;
// 當前容量爲:old容量 + (old容量 / 2) 對於>>可以理解爲 除以2的1次方
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 擴容後的容量 小於 當前容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 擴容後的容量 大於 arraylist最大容量時
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);
}
// 小編覺得很有必要講一下這個方法:擴容之後大於ArrayList的最大容量執行的hugeCapacity方法
有這麼幾個疑問:
1.爲什麼ArrayList的數組大小(MAX_ARRAY_SIZE)是:Integer.MAX_VALUE - 8?
2.爲什麼Integer.MAX_VALUE用0x7fffffff表示?
/**
* 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;
/**
* A constant holding the maximum value an {@code int} can
* have, 2<sup>31</sup>-1.
*/
@Native public static final int MAX_VALUE = 0x7fffffff;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
第一個問題:ArrayList的最大數組大小爲什麼是Integer.MAX_VALUE - 8?
剛開始小編也是到處找資料說是數組需要8 bytes去存儲它自己的大小,開始小編覺得這個回答有些敷衍,直到用翻譯工具截圖翻譯,這才解釋了源碼上這段可惡的英文,偶買噶,無形之中就暴露了小編的英文水平,請替我保密~~,哈哈哈哈哈哈
第二個問題:Integer.MAX_VALUE 爲什麼用0x7fffffff代表?
ox代表是16進制 7fffffff纔是16進制的值,簡單的說就是方便運算,計算器能理解的東西,我們不一定能理解。詳細可自行Google一下或找本基礎教材翻一下。
接下來講一點面試能扯到的實際東西。一般面試都只會問 ArrayList 的一些基本東西
1.比如ArrayList的底層實現是數組,數組的特點是:插入 刪除慢,查詢快
簡而言之就是數組刪除一個元素,需要把之後所有的元素向前移動,而查詢直接根據下標即可。
插入理解這個方法
Arrays.copyOf(原來的數組, 新的容量)
刪除理解這個方法:
例如: 現在有 1 2 3 4 這個數組集,我把 2 remove掉,後面 的 3 4 全部向前移一位
System.arraycopy(原來的集合, 移除的元素下一位的下標, 原來的集合, 移除的元素下標,要移動的數組個數);
Object arr[] = new Object[]{1, 2, 3, 4}; System.arraycopy(arr, 2, arr, 1, 2); arr[arr.length - 1] = null;// 移位替換之後,將最後一位數置空 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); }
2.arrayList 爲什麼是線程非安全呢?顯然沒有使用關鍵字加鎖 ,擴容大小是原來的0.5倍(oldSize + oldSize/2)=newSize
最近的專題是數據結構,有什麼好的提議或者不足歡迎留言交流
關注小編,點個贊留個評論也是對小編莫大的支持,謝謝各位小哥哥,小姐姐~
後面持續更新,地中海髮型尚未形成,小編仍需努力。。。。