ArrayList的底層實現原理數組
1, 屬性: 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; // 動態數組的實際大小 2,構造方法: public ArrayList(){ this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 調用無參的構造方法,則會將elementData賦上爲空的一個數組. public ArrayList(Collection<? extends E> c){ elementData = c.toArray(); if(size = elementData.length != 0){ if(elementData.getClass()!=Object[].class) elementData = Arrays.copyOf(elementData,size,Object[].class); }else{ elementData = EMPTY_ELEMENTDATA; } } 調用有參的構造方法,參數是一個帶範型的集合。生成一個能夠不爲空的集合。 若是參數使用toArray(),返回類型不是Object[],則使用copyOf() 複製下並賦值給elementData, public ArrayList(int initialCapacity){ if(initialCapacity > 0){ this.elementData = new Object[initialCapacity]; }else if(initialCapacicty == 0){ this.elementData = EMPTY_ELEMENTDATA; }else{ throw new IlleagalArgumentException("illagal initialCapacity"+initialCapcity); } } 調用有參的構造函數,初始化儲存元素的容量。定義以後,內存會爲開闢初始化容量大小的空間。 隨着ArrayList 裏面元素的增長直到initialCapacity,不須要數組向新數組的拷貝。 Tips: Arraylsit list = new ArrayList(10); 默認的Object[] elementData 的長度爲10; list.size();的長度仍是爲0 由於size 表明的邏輯長度,內存中實際存在的元素的長度。 3,add; 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(DEFAILT_CAPACITY,minCapacity); } ensureExplicitCapacity(minCapacity); } 向ArrayList 裏面增添元素的時候,當ArrayList 的爲空的時候,add元素時,若是沒有設定Arraylist的Object elementData的長度, 會設定默認的Object[] elementData 的長度爲10,因此在長度爲10 以前可以避免在每添加一個新的元素時候,就要複製原來的元素的數組到新的數組的裏面去。 private void ensureExplicitCapacity(int minCapacity){ modCount ++;//extends from AbstactArrayList if(minCapacity - elementData.length > 0) grow(minCapacity);//長度不夠,每次擴充1.5倍<粗略> } private void grow(int minCapacity){ int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if(newCapacity - minCapacity <0) newCapacity = minCapacity; if(newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //MAX_ARRAY_SIZE 2147483639 elementData = Arrays.copyOf(elementData,newCapacity);//擴充了Obect elementData[]的長度 } private void hugeCapacity(int minCapacity){ if(minCapacity < 0)//由於minCapacity int 型,超過int 的最大值就會<0,就表明內存溢出 throw new OutOfMemoryError(); return(minCapacity > Max_ARRAY_SIZE)?Integer.MAX_VALUE:MAX_ARRAY_SIZE; //最大上限就是Integer的最大值-8; } 4,add public void add(int index,E element){ rangeCheckForAdd(index); ensureCapacityInternal(size + 1); //開闢空間 System.arraycopy(elemntData,index,elementData,index + 1,size - index); size ++; } private void rangeCheckForAdd(int index){ if(index > size || index < 0 ){ throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } } add(int index,E elemenmt)中使用System.arraycopy的思想,是由於elementData的容器長度大於邏輯長度,即它自己的留有一個空位null,可用做填充數據。 例: Object [] elementData = {"one","two","three","four","five","null","null","null"}; 要想在index爲3的位置插入"six", System.arraycopy(elementData,3,elementData,4,2); elementData:源數組 3:源數組的起始位置 elementData:目標數組 4:目標數組的開始位置 2:size - index,size表明的是elementData中不爲null的元素的長度 因此,就能夠將index + 1 後半段的不爲null 的元素複製到源數組的自己,同時將index 這個位置空出來,而後插入就能夠實現add插入指定位置的功能。 elementData[index] = "six"; size ++; Arrays.copyOf(),System.copyof() system.arraycopy(Object src,int srcPos,Object dest,destPos,length);native 方法,源碼是由C++ 實現 Arrays.copyOf(),內部實現的也是System.arraycopy(),只是ArrayCopy()會建立一個新的數組,將源數組向新數組複製。 5,remove public E remove(int index){ rangeCheck(index);//先check下index有沒有有越界 modCount++;//非安全線程 E oldValue = elementData[index]; int numMoved = size - index - 1; if(numMoved > 0) System.arraycopy(elementData,index + 1,elementData,numMoved); //若是numMoved == 0 的狀況也就是源數組只有一個元素的狀況,就無需複製數組,只需執行elemnetData[--size]即elementData[0] =null elementData[--size] = null;//將elementData 的空間變成null return oldValue; } private void rangeCheck(int index){ if(index >= size){ throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } } 從必定程度上來講,remove(int index)的原理是和add(int index, E element)的邏輯是差很少的。 6,remove public boolean remove(Object o){ if(o == null){ for(int index = 0;index < size;i++){ if(elementData[index]==null){ fastRemove(index); return true; } } }else{ for(int index = 0;index < size;i++){ if(o.equals(elementData[index])){ fastRemove(index); return true; } } } return false; } private void fastRemove(index){ modCount++;//非安全線程 int numMoved = size - index - 1; if(numMoved > 0) System.arraycopy(elementData,index + 1,elementData,numMoved); elementData[--size] = null;//將elementData 的空間變成null } remove(Object o) 刪除集合中匹配的元素<最早匹配的元素>,其思路和remove(index)是同樣的 remove(index)是直接告知index,remove(Obejct o)是先找到匹配的index,而後再進行和remove(index) 大體的操做。 其中,remove(Obejct o)需考慮元素o 是否爲null,關於兩元素是否相等的比較方法== 和 equals == 在值類型中,就是比較值是否相等,可是在引用類型中,實際比較的是在內存中的地址是否相等 equals,是Obejct 中的方法,以下: public boolean equals(Object o){ return (this == o); } Object 是全部類的父類,Obejct 中的equals 方法就是==,是比較內存中的地址是否相等, 許多類會重寫Obejct 中的equals方法,例如String 類,重寫以後就是對字符串值進行比較 在remove(Obejct o) 中的equals 方法實際比較的就是內存中地址的相等。可是若是對於對Object中equals 方法重寫的類, 則實際比較的就是值是否相等。