概述
ArrayList實質上就是可變數組的實現,着重理解:add、get、set、remove、iterator的實現,我們將關注一下問題。
1、創建ArrayList的時候,默認給數組的長度設置為10。
2、當set、remove、set的時候,如何解決越界問題?
3、當add的時候,如何解決擴容問題?
4、由於數組是不可變的時候,我們需要頻繁重新新建數組重新賦值。
模擬實現
1、ArrayList定義變量與初始化。
//定義存儲數據的數組 private transient Object [] elementData; //容量大小 private int size; //默認構造器設置數組長度為10 public MyArrayList() { this(10); }</span><span style="color: #0000ff;">public</span> MyArrayList(<span style="color: #0000ff;">int</span><span style="color: #000000;"> capacity) { </span><span style="color: #0000ff;">super</span><span style="color: #000000;">(); </span><span style="color: #0000ff;">if</span>(capacity<0<span style="color: #000000;">){ </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IllegalArgumentException("數字不能小於0"<span style="color: #000000;">); } elementData</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[capacity]; }</span></pre>
2、解決越界問題:當索引值小於0或者索引值大於等於size就將越界。
public void rangeCheck(int index){ if(index<0 ||index>this.size){ throw new IndexOutOfBoundsException("越界"+index); } }
3、解決擴容問題:普通擴容(new=old+old*2)、索引值依然大於普通擴容(new=index)、當超過int的取值范圍(int的最大范圍-8)
public void ensureCapacity(int minCapacity){ if(minCapacity>elementData.length){ //獲得初始容器大小 int oldCapacity=elementData.length; //新的容器大小:初始容器大小+2初始容器大小(不懂為啥這樣加) int newCapacity=oldCapacity+(oldCapacity>>1); //當新增以后,還不能滿足索引長度,即將數組設置為最小索引長度 if(newCapacity<minCapacity){ newCapacity=minCapacity; } //當超過int的范圍的時候 if(minCapacity>Integer.MAX_VALUE-8){ newCapacity=Integer.MAX_VALUE-8; } Object [] elments=new Object[newCapacity]; //創建新的數組重新賦值。 System.arraycopy(elementData,0,elments,0,size); elementData=elments; } }
4、談談迭代器:hasNext():判斷是否有下一個、next():當前游標指向的值、remove():刪除剛變過過的元素;
private class Iter implements Iterator{ //游標 private int cursor=0; //指向剛遍歷過的元素 private int lastRet=0; public boolean hasNext() { return size!=cursor; }</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object next() { </span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">cursor; </span><span style="color: #0000ff;">if</span>(i>=<span style="color: #000000;">size){ </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> NoSuchElementException(); } cursor</span>=i+1<span style="color: #000000;">; </span><span style="color: #0000ff;">return</span> elementData[lastRet=<span style="color: #000000;">i]; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> remove() { </span><span style="color: #0000ff;">if</span>(cursor<0<span style="color: #000000;">){ </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalThreadStateException(); } MyArrayList.</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.remove(cursor); cursor</span>=<span style="color: #000000;">lastRet; </span><span style="color: #008000;">//</span><span style="color: #008000;">當刪除一個元素的時候,賦值為0</span> lastRet=-1<span style="color: #000000;">; } }</span></pre>
5、我相信樂忠於理解源碼的同學的基礎,弄清楚以上問題,應該ArrayList就沒有問題了。
public class MyArrayList<E> { //定義存儲數據的數組 private transient Object [] elementData; //容量大小 private int size; //默認構造器設置數組長度為10 public MyArrayList() { this(10); }</span><span style="color: #0000ff;">public</span> MyArrayList(<span style="color: #0000ff;">int</span><span style="color: #000000;"> capacity) { </span><span style="color: #0000ff;">super</span><span style="color: #000000;">(); </span><span style="color: #0000ff;">if</span>(capacity<0<span style="color: #000000;">){ </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IllegalArgumentException("數字不能小於0"<span style="color: #000000;">); } elementData</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[capacity]; } </span><span style="color: #0000ff;">public</span> E get(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index) { rangeCheck(index); </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (E) elementData[index]; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> set(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index, E element) { rangeCheck(index); ensureCapacity(index</span>+1<span style="color: #000000;">); E oldVlue</span>=<span style="color: #000000;"> (E) elementData[index]; </span><span style="color: #0000ff;">this</span>.elementData[index]=<span style="color: #000000;">element; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> add(E e) { ensureCapacity(size</span>+1<span style="color: #000000;">); elementData[size]</span>=<span style="color: #000000;">e; size</span>++<span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> add(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index, E element) { rangeCheck(index); ensureCapacity(index</span>+1<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">動態數組</span> System.arraycopy(elementData,index,elementData,index+1,size-<span style="color: #000000;">index); elementData[index]</span>=<span style="color: #000000;">element; size</span>++<span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;">移除</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> remove(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index) { rangeCheck(index); E oldVlue</span>=<span style="color: #000000;"> (E) elementData[index]; </span><span style="color: #0000ff;">int</span> moved=size-index-1<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(moved>0<span style="color: #000000;">) System.arraycopy(elementData,index</span>+1,elementData,index,size-<span style="color: #000000;">index);<br /> elementData[--size]=null; } </span><span style="color: #008000;">//</span><span style="color: #008000;">判斷是否越界</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> rangeCheck(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index){ </span><span style="color: #0000ff;">if</span>(index<0 ||index><span style="color: #0000ff;">this</span><span style="color: #000000;">.size){ </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IndexOutOfBoundsException("越界"+<span style="color: #000000;">index); } } </span><span style="color: #008000;">//</span><span style="color: #008000;">擴容</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> ensureCapacity(<span style="color: #0000ff;">int</span><span style="color: #000000;"> minCapacity){ </span><span style="color: #0000ff;">if</span>(minCapacity><span style="color: #000000;">elementData.length){ </span><span style="color: #008000;">//</span><span style="color: #008000;">獲得初始容器大小</span> <span style="color: #0000ff;">int</span> oldCapacity=<span style="color: #000000;">elementData.length; </span><span style="color: #008000;">//</span><span style="color: #008000;">新的容器大小:初始容器大小+2初始容器大小(不懂為啥這樣加)</span> <span style="color: #0000ff;">int</span> newCapacity=oldCapacity+(oldCapacity>>1<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">當新增以后,還不能滿足索引長度,即將數組設置為最小索引長度</span> <span style="color: #0000ff;">if</span>(newCapacity<<span style="color: #000000;">minCapacity){ newCapacity</span>=<span style="color: #000000;">minCapacity; } </span><span style="color: #008000;">//</span><span style="color: #008000;">當超過int的范圍的時候</span> <span style="color: #0000ff;">if</span>(minCapacity>Integer.MAX_VALUE-8<span style="color: #000000;">){ newCapacity</span>=Integer.MAX_VALUE-8<span style="color: #000000;">; } Object [] elments</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[newCapacity]; </span><span style="color: #008000;">//</span><span style="color: #008000;">創建新的數組重新賦值。</span> System.arraycopy(elementData,0,elments,0<span style="color: #000000;">,size); elementData</span>=<span style="color: #000000;">elments; } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> size(){ </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> size; } </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Iterator iterator(){ </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Iter(); } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">class</span> Iter <span style="color: #0000ff;">implements</span><span style="color: #000000;"> Iterator{ </span><span style="color: #008000;">//</span><span style="color: #008000;">游標</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> cursor=0<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">指向剛遍歷過的元素</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> lastRet=0<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> hasNext() { </span><span style="color: #0000ff;">return</span> size!=<span style="color: #000000;">cursor; } </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object next() { </span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">cursor; </span><span style="color: #0000ff;">if</span>(i>=<span style="color: #000000;">size){ </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> NoSuchElementException(); } cursor</span>=i+1<span style="color: #000000;">; </span><span style="color: #0000ff;">return</span> elementData[lastRet=<span style="color: #000000;">i]; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> remove() { </span><span style="color: #0000ff;">if</span>(cursor<0<span style="color: #000000;">){ </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalThreadStateException(); } MyArrayList.</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.remove(cursor); cursor</span>=<span style="color: #000000;">lastRet; </span><span style="color: #008000;">//</span><span style="color: #008000;">當刪除一個元素的時候,賦值為0</span> lastRet=-1<span style="color: #000000;">; } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String [] args){ MyArrayList ls</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> MyArrayList(); ls.add(</span>123<span style="color: #000000;">); ls.add(</span>123<span style="color: #000000;">); ls.set(</span>0,456<span style="color: #000000;">); ls.remove(</span>1<span style="color: #000000;">); System.out.println(ls.size()); System.out.println(ls.get(</span>0<span style="color: #000000;">)); Iterator it</span>=<span style="color: #000000;">ls.iterator(); </span><span style="color: #0000ff;">while</span><span style="color: #000000;">(it.hasNext()){ System.out.println(it.next()); } }}
