JAVA容器-模擬ArrayList的底層實現


概述

  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&lt;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&gt;=<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&lt;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&lt;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&gt;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&lt;0 ||index&gt;<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&gt;<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&gt;&gt;1<span style="color: #000000;">);
        </span><span style="color: #008000;">//</span><span style="color: #008000;">當新增以后,還不能滿足索引長度,即將數組設置為最小索引長度</span>
        <span style="color: #0000ff;">if</span>(newCapacity&lt;<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&gt;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&gt;=<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&lt;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());
    }

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM