Java基礎面試題(18)----ArrayList集合原始碼解析
阿新 • • 發佈:2018-12-13
我們對ArrayList集合的原始碼進行解析,只是寫出了增刪改查的方法。
首先我們來看一下ArrayList的資料結構
- 底層實際上是一個數組,在增加元素的時候,對陣列進行擴容,新增一個元素,容量增加1。
- 實際儲存的是順序儲存的結構,每個位置的元素都有執行的索引,所以可以實現快速的查詢元素。 用簡單的圖片展示,如下:
- 但是當在指定位置新增元素的時候,後面位置的元素統一向後移動,效率較低,這裡會呼叫系統的複製陣列的方法,因為無法看到原始碼,所以內有辦法深入研研究,這段程式碼如下:
- 移除元素的圖片展示如下
//複製陣列 System.arraycopy(elementData, index+1, elementData, index, numMoved);
那我們簡單的看一下ArrayList的內部程式碼實現
package com.mainshi.mylist; import java.io.Serializable; import java.util.AbstractList; import java.util.Arrays; import java.util.List; import java.util.RandomAccess; public class MyArrayList<E> extends AbstractList implements List,RandomAccess,Cloneable,Serializable{ //首先定義成員變數 //靜態常量值,UID private static final long serialVersionUID = 8683452581122892189L; //預設容量 private static final int DEFAULT_CAPACITY = 10; //空的元素資料 private static final Object[] EMPTY_ELEMENTDATA = {}; // private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //非序列化物件陣列 transient Object[] elementData; //長度 private int size; //構造方法 public MyArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } public MyArrayList(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); } } @Override//獲取數值的方法 public Object get(int index) { if(index>=size){ throw new IndexOutOfBoundsException(); } return elementData[index]; } //獲取長度 @Override public int size() { return size; } //新增的方法 @Override public boolean add(Object o) { //擴容的方法 ensureCapacityInternal(size + 1); //將新的元素賦值給最末尾的長度 elementData[size++]=o; return true; } //擴容的方法 private void ensureCapacityInternal(int minCapacity) { //三元運算子,如果現在的集合大小不等於預設的長度(建構函式有確認),最小擴容為0, //如果相等,最小擴容為10 int minExpand=(elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0:DEFAULT_CAPACITY; //輸入的長度大於擴容的長度 if (minCapacity>minExpand){ ensureExplicitCapacity(minCapacity); } } private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity-elementData.length>0){ grow(minCapacity); } } //常見一個新的陣列,長度比之前的陣列加1; private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } //在指定的索引位置新增元素 public void add(int index,Object obj){ //資料合法性檢查 rangCheck(index); //擴容 ensureCapacityInternal(size + 1); //賦值陣列 System.arraycopy(elementData, index, elementData, index + 1, size - index); //將元素裝到對應位置 elementData[index] = obj; //集合長度增加 size++; } private void rangCheck(int index) { if (index>size || index<0){ throw new IndexOutOfBoundsException("指定元素的位置"+index+"超出集合的長度"); } } //移除指定位置的元素的方法 public E remove(int index){ //合法性檢查 rangCheck(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; } //提取元素的方法 E elementData(int index) { return (E) elementData[index]; } //移除指定的物件 public boolean remove(Object object){ if (object==null){//如果執行物件為null for (int index=0;index<size;index++){ if(elementData(index)==null){ fastRemove(index); return true; } } }else{//如果指定物件部位null for (int index=0;index<size;index++){ if(elementData(index).equals(object)){ fastRemove(index); return true; } } } return false; } 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 } //修改元素的放法 public Object set(int index,Object object){ //範圍檢查 rangCheck(index); //取出舊元素 Object oldValue = elementData(index); //指定位置放入新的元素 elementData[index]=object; //返回舊的元素 return oldValue; } }