概述
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()); } }
}