標籤:固定 java數組 collect exception 插入 myarray lis color range
package test;import java.util.Arrays;import java.util.Collection;public class MyArrayList<E> { //儲存資料 private Object[] values; //已經使用的容量 private int size; //修改次數 private int modCount; /** * 根據給定容量初始化 * @param initialCapacity */ public MyArrayList(int initialCapacity){ if(initialCapacity > 0){//按照給定的容量大小初始化數組 values = new Object[initialCapacity]; }else if(initialCapacity == 0){ values = new Object[]{}; }else{ throw new IllegalArgumentException("非法初始化容量: "+ initialCapacity); } } /** * 預設初始化方法 */ public MyArrayList(){ this(10); } /** * 用集合初始化一個ArrayList * @param c */ public MyArrayList(Collection c){ values = c.toArray(); if (values.length != 0) { size = values.length; if (values.getClass() != Object[].class) values = Arrays.copyOf(values, size, Object[].class); }else{ values = new Object[]{}; } } /** * 檢查是否數組越界了 * @param index */ private void rangeCheck(int index) { if (index >= size || index < 0) throw new IndexOutOfBoundsException("數組越界了"); } /** * 替換原數組中的值,並且將原值返回 * @param index * @param element * @return */ public E set(int index,E element){ //檢查是否越界 rangeCheck(index); E oldValue = (E)values[index]; values[index] = element; return oldValue; } /** * 在數組的末尾增加一個元素 * @param element */ public void add(E element){ //擴容 ensureCapacity(size+1); values[size++] = element; } /** * @param index * @param element */ public void add(int index,E element){ //先檢查數組的下標是否越界了 rangeCheck(index); //擴容 ensureCapacity(size+1); Object[] oldValues = values; values[index] = element; //將原數組index後的值拷貝帶新數組中 System.arraycopy(oldValues, index, values, index+1, size-index); size++; } /** * 將一個collection中的元素添加到數組末尾 * @param c */ public void addAll(Collection c){ Object[] cArray = c.toArray(); //擴容 ensureCapacity(size+cArray.length); //將傳入資料拷貝到數組末尾 System.arraycopy(cArray, 0, values, size, cArray.length); size += cArray.length; } /** * 將一個collection中的元素添加到數組的指定位置 * @param index * @param c */ public void addAll(int index,Collection c){ //先檢查數組的下標是否越界了 rangeCheck(index); //擴容 Object[] cArray = c.toArray(); int cLength = cArray.length; ensureCapacity(size+cLength); Object[] oldValues = values; //將傳入資料拷貝到數組指定位置 System.arraycopy(cArray, 0, values, index, cLength); //將原數組中index以後的資料拷貝過來 System.arraycopy(oldValues, index, values, values.length-1, size-index); size += cLength; } /** * 根據下標擷取元素 * @param index * @return */ public E get(int index){ //先檢查數組的下標是否越界了 rangeCheck(index); E e = (E) values[index]; return e; } /** * 根據下標刪除元素 * @param index * @return */ public E remove(int index){ //先檢查數組的下標是否越界了 rangeCheck(index); E removeValue = (E) values[index]; System.arraycopy(values, index+1, values, index, size-index-1); //置為空白,gc回收 values[size--] = null; return removeValue; } /** * 根據對象刪除 * @param o */ public void remove(Object o){ //考慮元素為null的情況 if(null == o){ for (int i = 0; i < size; i++) { if(values[i] == null){ remove(i); } } }else{ for (int i = 0; i < size; i++) { if(values[i].equals(o)){ remove(i); } } } } /** * 擴容方法,保證數組的長度足夠 * @param minCapacity */ public void ensureCapacity(int minCapacity){ modCount++; int oldCapacity = values.length; if (minCapacity > oldCapacity) { //先預設擴容50%+1,如果還是不能滿足,則直接用傳入的所需容量 int newCapacity = (oldCapacity*3)/2+1; if(newCapacity < minCapacity){ newCapacity = minCapacity; } values = Arrays.copyOf(values, newCapacity); } } public int size(){ return size; } }
最後再介紹一下ensureCapacity這個方法的想法(從網上看到的):
我們知道ArrayList的內部是採用數組來儲存元素的,由於java數組都是定長的,所以這個數組的大小一定是固定的,這個大小就是capacity。我們可以肯定capacity一定是大於或等於ArrayList的size,那麼當size不斷增加到了要超過capacity的時候,ArrayList就不得不重新建立新的capacity來容納更多的元素,這時需要首先建立一個更長的數組,將原來的數組中的元素複製到新數組中,再刪除原來的數組。可見當ArrayList越來越大時,這種操作的消耗也是越來越大的。
為了減少這種不必要的重建capacity的操作,當我們能肯定ArrayList大致有多大(或者至少會有多大)時,我們可以先讓ArrayList把capacity設為我們期望的大小,以避免多餘的數組重建。
假設ArrayList自動把capacity設為10,每次重建時將長度遞增原來的三分之二,那麼當我們需要大約儲存50個元素到ArrayList中時,就會大約需要重建數組4次,分別是在增加第11、第17、第26、第39個元素的時候進行的。如果我們一開始就讓ArrayList的capacity為50,那麼不需要任何數組重建就能完成所有插入操作了。
java允許我們在構造ArrayList的同時指定capacity,如new ArrayList(50),也允許在以後將它設得更大,而增大capacity就是使用ensureCapacity()方法。注意:capacity只能比原來的更大,而不能比原來的更小,否則java會忽略該操作。ArrayList的初始預設capacity為10,所以給capacity指定小於10的整數是毫無意義的。
最後說說ArrayList的size,前面說過,size一定小於等於capactiy,而且更重要的是,訪問超過size的位置將拋出異常,儘管這個位置可能沒有超過capacity。ensureCapacity()只可能增加capacity,而不會對size有任何影響。要增加size,只能用add()方法。
Java ArrayList的類比實現