Java ArrayList 實現執行個體講解_java

來源:互聯網
上載者:User

 ArrayList概述: 

ArrayList是基於數組實現的,是一個動態數組,其容量能自動成長,類似於C語言中的動態申請記憶體,動態增長記憶體。

    ArrayList不是安全執行緒的,只能用在單線程環境下,多線程環境下可以考慮用Collections.synchronizedList(List l)函數返回一個安全執行緒的ArrayList類,也可以使用concurrent並發包下的CopyOnWriteArrayList類。

    ArrayList實現了Serializable介面,因此它支援序列化,能夠通過序列化傳輸,實現了RandomAccess介面,支援快速隨機訪問,實際上就是通過下標序號進行快速存取,實現了Cloneable介面,能被複製。

   每個ArrayList執行個體都有一個容量,該容量是指用來儲存列表元素的數組的大小。它總是至少等於列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動成長。自動成長會帶來資料向新數組的重新拷貝,因此,如果可預知資料量的多少,可在構造ArrayList時指定其容量。在添加大量元素前,應用程式也可以使用ensureCapacity操作來增加ArrayList執行個體的容量,這可以減少遞增式再分配的數量。 

   注意,此實現不是同步的。如果多個線程同時訪問一個ArrayList執行個體,而其中至少一個線程從結構上修改了列表,那麼它必須保持外部同步。

下面對java arraylist做一個記錄和總結吧

public class arraylist<E> {  /**   * 存放集合的元素    *    */  private transient Object[] elementData;  /** 元素的大小 */  private int size;

定義了一個泛型類,一個object的數組和一個私人變數來記錄該集合的元素數量,原文多了一個私人變數,我也不知道幹嘛用的,作者也沒解釋也沒提及到,我沒使用也沒事

/**   * 根據指定大小初始化   * @param initialCapacity   */  public arraylist(int initialCapacity){    super();    if(initialCapacity<=0){      //拋異常      throw new IllegalArgumentException("初始化參數不能小於0");    }else{      //初始化數組      this.elementData=new Object[initialCapacity];    }  }  /**   * 預設初始化   */  public arraylist(){    this(10);  }  /**   * 根據一個集合類初始化   * @param c 一個必須繼承了Collection介面的類   */  public arraylist(Collection<? extends E> c){    //初始化    elementData=c.toArray();    size=elementData.length;    //如果不是任意類型的數組就轉換Objec類型    if (elementData.getClass() != Object[].class){      elementData=Arrays.copyOf(elementData,size, Object[].class);    }  }

3個初始化方法,根據預設大小進行數組的初始化,給定大小初始化和傳遞一個繼承了Collection集合介面的類進行轉換賦值初始化

/**   * 擴容集合   * @param minCapacity   */  public void ensureCapacity(int minCapacity){    /** 當前數組的大小 */    int oldCapacity = elementData.length;     if (minCapacity > oldCapacity) {      /**       * oldData 雖然沒有被使用,但是這是關於記憶體管理的原因和Arrays.copyOf()方法不是安全執行緒       * oldData在if的生命週期內引用elementData這個變數,所以不會被GC回收掉       * 當Arrays.copyOf()方法在把elementData複製到newCapacity時,就可以防止新的記憶體或是其他線程分配記憶體是elementData記憶體被侵佔修改       * 當結束是離開if,oldData周期就結束被回收       */      Object oldData[] = elementData;       int newCapacity = (oldCapacity * 3)/2 + 1; //增加50%+1        if (newCapacity < minCapacity)           newCapacity = minCapacity;      //使用Arrays.copyOf把集合的元素複製並產生一個新的數組     elementData = Arrays.copyOf(elementData, newCapacity);     }   }

這是一個核心的方法,集合的擴容,其實是對數組的擴容,minCapacity集合的大小,進行對比判斷是否應該進行擴容,使用了Arrays.copyOf()方法進行擴容,

原文有進行詳細的解釋,這個方法把第一個參數的內容複寫到一個新的數組中,數組的大小是第二個參數,並返回一個新的數組,關於oldData的變數上文有詳細的注釋

 /**   * 檢查索引是否出界   * @param index   */  private void RangeCheck(int index){    if(index > size || index < 0){      throw new IndexOutOfBoundsException("下標超出,Index: " + index + ", Size: " +size);    }  }

一個下標的檢索是否出 1 /**

* 添加元素   * 將指定的元素添加到集合的末尾   * @param e 添加的元素   * @return   */  public boolean add(E e){    ensureCapacity(size+1);    elementData[size]=e;    size++;    return true;  }

添加元素,先進行擴容,在賦值,然後元素加一,注意 size+1 欄位size並沒有加一,這裡進行的是算術的運算,所以在後面才需要進行自增

/**   * 添加元素   * 將元素添加到指定的位置   * @param index 指定的索引下標   * @param element 元素   * @return   */  public boolean add(int index, E element){    RangeCheck(index);    ensureCapacity(size+1);    // 將 elementData中從Index位置開始、長度為size-index的元素,     // 拷貝到從下標為index+1位置開始的新的elementData數組中。     // 即將當前位於該位置的元素以及所有後續元素右移一個位置。    System.arraycopy(elementData, index, elementData, index+1, size-index);    elementData[index]=element;    size++;//元素加一    return true;  }

這裡不同的是 System.arraycopy(elementData, index, elementData, index+1, size-index);

這是一個c的內部方法,詳細的原文有解釋,這裡就不說了,這個也是整個ArrayList的核心所在,也Arrays.copyOf()的內部實現原理

/**   * 添加全部元素   * 按照指定collection的迭代器所返回的元素順序,將該collection中的所有元素添加到此列表的尾部。    * @param c   * @return   */  public boolean addAll(Collection < ? extends E>c){    Object[] newElement=c.toArray();    int elementLength=newElement.length;    ensureCapacity(size+elementLength);    //從newElement 0的下標開始,elementLength個元素,elementData size的下標     System.arraycopy(newElement, 0, elementData, size, elementLength);    size+=elementLength;    return elementLength!=0;  }

基本上其他方法都只是根據不同的情況進行不同的處理,比如通過介面把資料對象傳遞進來然後擷取長度進行擴容,在把資料使用System,arraycopy複製到新的數組中

/**   * 指定位置,添加全部元素   * @param index 插入位置的下標   * @param c 插入的元素集合   * @return   */  public boolean addAll(int index, Collection<? extends E> c){    if(index > size || index < 0){      throw new IndexOutOfBoundsException("Index: " + index + ", Size: " +size);    }    Object[] newElement=c.toArray();    int elementLength=newElement.length;    ensureCapacity(size+elementLength);    int numMoved=size-index;    //判斷插入的位置是否在數組中間    if(numMoved>0){      //把index插入位置的後面的所有元素往後移      //elementData index下標開始的numMoved個元素插入到elementData 的index+elementLength位置      System.arraycopy(elementData, index, elementData, index+elementLength, numMoved);    }    //把newElement裡從0開始的elementLength個元素添加到elementData index開始的位置    System.arraycopy(newElement, 0, elementData, index, elementLength);     size += elementLength;     return elementLength != 0;  }    /**   * 指定下標賦值   * @param index   * @param element   * @return   */  public E set(int index,E element){    RangeCheck(index);    E oldElement=(E)elementData[index];    elementData[index]=element;    return oldElement;  }    /**   * 根據下標取值   * @param index   * @return   */  public E get(int index){    RangeCheck(index);    return (E)elementData[index];  }    /**   * 根據下標移除元素   * @param index    */  public E remove(int index){    RangeCheck(index);    E oldElement=(E)elementData[index];    /** 移除的下標後面的元素數量 */    int numMoved=size-index-1;    //如果在數組範圍內就進行移動    if(numMoved>0)      System.arraycopy(elementData, index+1, elementData, index, numMoved);    //移除    elementData[--size]=null;    return oldElement;  }    /**   * 根據元素移除   * @param obj   * @return   */  public boolean remove(Object obj){    //Arraylist允許存放null,所以也要進行判斷處理    if(obj==null){      for(int index=0;index<size;index++){        if(elementData[index]==null){           remove(index);           return true;        }      }    }else{      for(int index=0;index<size;index++){        if(obj.equals(elementData[index])){           remove(index);           return true;        }      }    }    return false;  }    /**   * 根據下標移除指定範圍內的元素   * @param fromIndex 開始   * @param toIndex 結束   */  protected void removeRange(int fromIndex, int toIndex){    RangeCheck(fromIndex);    RangeCheck(toIndex);    //要移動的元素數    int numMoved = size - toIndex;     //把toIndex後面的元素移動到fromIndex    System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);    //要移除的元素數量    int newSize=size-(toIndex-fromIndex);    while(size!=newSize){      elementData[--size]=null;    }   }    /**   * 把數組容量調整到實際的容量   */  public void trimToSize(){    int leng=elementData.length;    if(size<leng){      Object[] old=elementData;      elementData=Arrays.copyOf(elementData, size);    }  }  /**   * 把集合元素轉換成數組   * @return   */  public Object[] toArray(){    return Arrays.copyOf(elementData, size);  }    public <T>T[] toArray(T[] a){    if(a.length<size){      return (T[]) Arrays.copyOf(elementData,size, a.getClass());    }    //把集合元素複製到a數組中    System.arraycopy(elementData, 0, a, 0, size);     if (a.length > size){       for(int index=size;index<a.length;index++){         a[index] = null;       }     }     return a;   }

基本上都是對數組進行操作和使用c的方法進行賦值移動等,詳細的可以查看原文,原文中除了那個私人變數外也沒多少問題,代碼可以完美運行,這李要注意的和痛點就會是System,arraycopy和Arrayist.copy()這2個方法
和在擴容方法裡oldData這個變數的使用,這個變數真的很好,一開始我也不知道為什麼要這麼使用,在原文的末尾會進行解釋。

以上所述是小編給大家介紹的Java ArrayList 實現執行個體講解,希望對大家有所協助,如果大家有任何疑問歡迎給我留言,小編會及時回複大家的,在此也非常感謝大家對雲棲社區網站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.