注:轉載請注明原文地址:http://www.cnblogs.com/ygj0930/p/5965205.html
代碼已移植:https://github.com/ygj0930/MyArrayList 大家fork之余隨手給我個star呀~
ArrayList是我們常用的集合類之一,其實它的實現機制很簡單,底層還是使用了一個傳統的Array數組來保存數據的。而動態的實現,只不過是定義了其在長度不足時創建一個更大的數組並把原數組的數據復制過去罷了!而對其保存的數據的增刪查該操作,也只不過是封裝了一系列最基本的操作數組數據的動作而已。下面,我把自己實現的簡略版ArrayList貼上來,供伙伴們參考。
public class MyArrayList<E> { public transient E[] elements;//底層的泛型數組用來保存元素 /* 這里用transient修飾數組,用transient關鍵字標記的成員變量不參與序列化過程。 serialization(序列化)提供了一種持久化對象實例的機制,通過序列化可以把對象輸出到文檔中保存。 而不想某個對象參與序列化,就可以用transient把該對象排除在外。 */ public int size;//size記錄數組當前的有效元素個數 //實現三個構造方法 public MyArrayList(int n) { if (n > 0) { this.elements = (E[])new Object[n];//創建容量為n的數組 this.size=0;//一開始數組里個數為0 } else { throw new IllegalArgumentException("Illegal Capacity: "+n); } } public MyArrayList() { this.elements = (E[])new Object[10]; this.size=0; } public MyArrayList(Collection<Object> c) { elements = (E[])c.toArray();//將集合轉換為數組,數組容量為集合元素個數 if ((size = elements.length) != 0) { //此時數組元素個數等於數組容量 elements = (E[])Arrays.copyOf(elements, size, Object[].class);} } //實現容量擴充 public void ensureCapacity(int newCapacity){ int curr=elements.length; if(newCapacity>curr){ elements=Arrays.copyOf(elements, newCapacity); } } //調整底層數組容量以契合當前元素數量,避免空元素部分太多而浪費內存。size是數組中實際存在的元素個數 public void trimToSize(){ int curr=elements.length; if(size<curr){ elements=Arrays.copyOf(elements, size); } } //實現下標檢查:避免訪問越界內存 public void rangeCheck(int requestIndex){ if(requestIndex<0||requestIndex>size){ throw new IndexOutOfBoundsException(); } } //實現基本操作:增、刪、查、改 //增 //在某個位置插入新元素 public void add(int index,E element){ this.rangeCheck(index);//先檢查插入位置的合法性 //再檢查當前數組元素個數是否已經達到最大值,即達到數組容量,是,則擴充數組 if(size==elements.length){ ensureCapacity(elements.length*2+1); } //將插入位置的原數據以及其后的數據往后移動一位,騰出空間 System.arraycopy(elements, index, elements, index+1, 1); //插入相應位置,並將數組元素個數加一 elements[index]=element; ++size; } //在數組末尾追加一個元素 public void add(E element){ this.add(size, element);//實則等同於在elements[size]處插入元素 } //將一個集合插入到數組某位置 public void addAll(int index,Collection<? extends E> c){ rangeCheck(index); //獲取插入元素以及個數 E[] newEs=(E[])c.toArray(); int newLength=newEs.length; //擴充數組容量 ensureCapacity(size+newLength+1); //計算插入位置以及其后元素的個數,即:需要右移的元素個數 int move=size-index; //調用System.arraycopy()方法進行數組的大量數據移動操作。 /* public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 方法解讀:第一個參數指明數據的來源數組,第二個參數說明數據源的起始位置 第三個參數說明數據去向的目標數組,第四個參數說明數據在目標數組中存放時的起始位置,最后一個參數說明移動的數據長度(個數)。 該函數調用了C語言的memmove()函數,比一般的復制方法的實現效率要高很多,也安全很多,很適合用來批量處理數組。 強烈推薦在復制大量數組元素時用該方法,以取得更高的效率。 */ //將原數組index~size范圍的元素移動,騰出位置 if(move>0){ System.arraycopy(elements, index, elements, index+newLength, move); } //將插入數組元素復制到elements數組中騰出的位置 System.arraycopy(newEs,0 , elements, index, newLength); size+=newLength;//元素個數增加 } //將一個集合插入到數組末尾 public void addAll(Collection<? extends E> c){ this.addAll(size, c);//相當於在原數組elements[size]處開始,插入一個集合 } //刪 //移除指定位置的元素 public E remove(int index){ rangeCheck(index); E oldelement=elements[index]; //原位置后面的元素左移 System.arraycopy(elements, index+1, elements, index, size-index-1); elements[size]=null;//修改原數組最后一個元素位置為空 --size;//修改元素個數 return oldelement; } //移除某個值的元素 public boolean remove(E element){ boolean index=false; for(int i=0;i<size;++i){ if(element.equals(elements[i])){//若找到該值 index=true;//說明有該值,可以執行移除,結果為true。否則,結果false this.remove(i);//則通過下標來移除 } } return index; } //移除某個 范圍內 的元素(不包括end) public void removeRange(int start,int end){ int move=size-end; System.arraycopy(elements, end,elements, start, move); //修改左移留下的位置為空 for(int i=size-1;i>(size-(end-start)-1);--i){ elements[i]=null; } size-=(end-start); } //查 //獲取某位置的元素 public E get(int index){ rangeCheck(index); return elements[index]; } //改 //修改某位置的元素 public void set(int index,E newElement){ rangeCheck(index); elements[index]=newElement; } //轉變為普通數組 public E[] toArray() { E[] array=(E[]) new Object[size]; System.arraycopy(elements, 0,array,0, size); return array; } public static void main(String[] args) { MyArrayList<Integer> testMyArrayList=new MyArrayList<Integer>(); System.out.println(testMyArrayList.size); testMyArrayList.add(1); testMyArrayList.add(2); testMyArrayList.add(3); testMyArrayList.add(4); testMyArrayList.add(5); System.out.println(testMyArrayList.size); System.out.println(testMyArrayList.get(3)); testMyArrayList.removeRange(1, 3); System.out.println(testMyArrayList.size); System.out.println(testMyArrayList.get(2)); } }
