package myList;import java.util.Arrays;import java.util.ConcurrentModificationException;import java.util.Iterator;/** * 一個類比arraylist的簡單的集合類 * * @author 薑俠 * * @param <E> */public class MyArrayList<E> implements MyList<E>, java.io.Serializable {private static final long serialVersionUID = 298503308405784327L;/* * 在設計一個動態數組的時候,其本質就是一個數組, * 所以,該類中應該存在至少2個屬性, * 1.數組elementData * 2.數組實際大小size *//** * 數組 transient修飾符:被修飾對象在流的傳輸過程中不會被保留 * (被修飾對象其類必須實現java.io.Serializable介面) *elementData是一個緩衝數組,它通常會預留一些容量,等容量不足時再擴充容量, *這個樓主一定是明白的,不用多解釋。假如現在實際有了5個元素,而elementData的大小可能是10, *那麼在序列化時只需要儲存5個元素,數組中的最後五個元素是沒有實際意義的,不需要儲存。 *elementData設計為transient,然後在writeObject方法中手動將其序列化, *並且只序列化了實際儲存的那些元素,而不是整個數組 * (實際是重構一個數組使其大小=資料個數) */@SuppressWarnings("unused")private transient Object[] elementData;/** * 數組實際大小(size=資料個數) */@SuppressWarnings("unused")private int size;/** * 記錄動態數組重構的次數 */private transient int modCount = 0;/* * 動態數組的第一次體驗就是在建立的時候, * 我們無需給定數組的大小就可直接建立出我們想要的數組; * 這都歸功於動態數組中的構造方法。 * 我們的構造方法將設定2個 * 1.無參構造,但是數組的聲明必須需要一個初始大小,所以我們將在無參構造中給數組一個初始值 * 2.有參構造(數組大小),有時候我們知道資料的個數, * 所以想手動的設定數組的大小,以減少動態數組在建立數組時候的開銷 * 3.有時我們會想到將一個數群組轉換成一個動態數組 *//** * 無參構造,但是數組的聲明必須需要一個初始大小, * 所以我們將在無參構造中給數組一個初始值 */public MyArrayList() {this(10);}/** * 有參構造(數組大小),有時候我們知道資料的個數, * 所以想手動的設定數組的大小,以減少動態數組在建立數組時候的開銷 * @param elementSize * 設定數組大小 */public MyArrayList(int elementSize) {if (elementSize < 0) {throw new IllegalArgumentException("您的數組大小設定有誤: " + elementSize);} else {this.elementData = new Object[elementSize];}}/** * 將動態數組的容量設定為實際數組的大小(容量 = 實際大小) */public void trimToSize() {this.modCount++;int oldElementSize = this.elementData.length;if (this.size < oldElementSize) {// Arrays.copyOf()與system.arraycopy()作用一樣,只是arraycopy()需要指定原數組,//原數組起始位置,目的數組和目的數組放置的起始位置,複製長度// 顯然比較死板,所以用copyOf()直接將目的數組和複製長度傳入進行全部複製this.elementData = Arrays.copyOf(this.elementData, size);//jdk1.6新添方法}}/** * 確定動態數組容量 如果數組當前容量不夠裝載資料,則進行擴容 * @param minCapacity * 實際大小+1(表示添加的資料座標) */public void ensureCapacity(int minCapacity) {this.modCount++;// 拿到當前數組長度int oldElementSzie = this.elementData.length;// 最小容量與當前數組長度對比// 如果最小容量>當前數組長度,根據黃金分割逆向思維,建立新的數組長度來重構數組if (minCapacity > oldElementSzie) {int newElementSize = (oldElementSzie * 3) / 2 + 1;// 如果最小容量>新數組長度,則將新數組長度=最小容量,因為最小容量通常是接近的大小,所以這是一個雙贏if (minCapacity > newElementSize) {newElementSize = minCapacity;}this.elementData = Arrays.copyOf(this.elementData, newElementSize);}}@Overridepublic int size() {return this.size;}@Overridepublic boolean isEmpty() {return this.size == 0;}@Overridepublic boolean contains(Object obj) {return indexOf(obj) >= 0;}@Overridepublic Iterator<E> iterator() {return null;}@Overridepublic Object[] toArray() {return java.util.Arrays.copyOf(elementData, size);}@Overridepublic boolean add(E e) {// 先判斷是否進行擴充this.ensureCapacity(this.size + 1);// 添加資料this.elementData[size++] = e;return true;}@Overridepublic boolean remove(Object o) {// 判斷對象是否為空白// 對象為空白,則遍曆數組,尋找第一個為空白的對象進行刪除if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {// 刪除方法fastRemove(index);return true;}} else {// 對象不為空白,則遍曆數組,尋找第一個與該對象匹配的元素嗎,進行刪除for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {// 刪除方法fastRemove(index);return true;}}return false;}@Overridepublic boolean containsAll(MyList<E> list) {int temp = 0;for (int i = 0; i < list.size(); i++) {if (this.contains(list.get(i))) {temp++;}}if (temp == list.size()) {return true;}return false;}@Overridepublic boolean removeAll(MyList<E> list) {for (int i = 0; i < list.size(); i++) {if (this.contains(list.get(i))) {this.remove(list.get(i));}}return true;}@Overridepublic boolean addAll(MyList<E> list) {int numNew = list.size();// 是否擴容ensureCapacity(size + numNew); // Increments modCount// 元素右移System.arraycopy(list.toArray(), 0, elementData, size, numNew);// 更新數組實際大小size += numNew;return numNew != 0;}@Overridepublic boolean addAll(int index, MyList<E> list) {// 判斷索引是否符合要求if (index > size || index < 0)throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);int numNew = list.size();// 是否擴容ensureCapacity(size + numNew); // Increments modCountint numMoved = size - index;if (numMoved > 0)System.arraycopy(elementData, index, elementData, index + numNew,numMoved);System.arraycopy(list.toArray(), 0, elementData, index, numNew);size += numNew;return numNew != 0;}@Overridepublic boolean retainAll(MyList<E> list) {// 判斷參數數組是否為空白,如果為空白則清空elementDataif (list.size() == 0) {this.clear();}Object[] newObjs = new Object[list.size()];int temp = 0;// 判斷交集是否為空白// 遍曆參數數組for (int i = 0; i < list.size(); i++) {// 與數組中的每一個元素進行對比// 如果有相同的元素,則建立一個新的elementData,將一致的資料放入新的數組中if (this.contains(list.get(i))) {newObjs[i] = list.get(i);temp++;}}if (temp == 0) {this.clear();} else {this.elementData = Arrays.copyOf(newObjs, newObjs.length);this.size = newObjs.length;}return true;}@Overridepublic void clear() {// 重構數組次數+1modCount++;// 遍曆數組,就所有的元素設為空白for (int i = 0; i < size; i++)elementData[i] = null;// 數組實際大小為0size = 0;}@Overridepublic E get(int index) {rangeCheck(index);return (E) elementData[index];}@Overridepublic E set(int index, E element) {rangeCheck(index);Object oldElement = this.elementData[index];this.elementData[index] = element;return (E) oldElement;}@Overridepublic void add(int index, E element) {// 判斷索引是否符合要求if (index > size || index < 0)throw new IndexOutOfBoundsException("Index: " + index + ", Size: "+ size);// 判斷是否需要擴容ensureCapacity(size + 1); // Increments modCount!!// 將元素按照指定索引右移(實現數組複製)System.arraycopy(elementData, index, elementData, index + 1, size- index);// 添加新元素elementData[index] = element;// 跟新數組實際大小size++;}@Overridepublic E remove(int index) {// 判斷索引是否越界rangeCheck(index);// 增加更改次數modCount++;// 擷取index指定的元素E oldValue = (E) elementData[index];// 擷取該元素後一個索引int numMoved = size - index - 1;// 判斷如果索引大於0,則存在元素,將元素左移(其實實現了數組複製)if (numMoved > 0)System.arraycopy(elementData, index + 1, elementData, index,numMoved);elementData[--size] = null; // Let gc do its workreturn oldValue;}@Overridepublic int indexOf(Object o) {// 判斷對象是否為空白// 如果為空白則迴圈遍曆數組,對比那個元素是空,返回第一個匹配的元素的索引indexif (o == null) {for (int i = 0; i < this.size; i++) {if (this.elementData[i] == null) {return i;}}} else {// 如果不為空白則迴圈遍曆數組,對比每一個元素,返回第一個匹配的元素的索引indexfor (int i = 0; i < this.size; i++) {if (this.elementData[i].equals(o)) {return i;}}}// 否則返回-1return -1;}@Overridepublic int lastIndexOf(Object o) {// 判斷對象是否為空白// 如果為空白則迴圈遍曆數組,對比那個元素是空,返回第一個匹配的元素的索引indexif (o == null) {for (int i = this.size - 1; i >= 0; i--) {if (this.elementData[i] == null) {return i;}}} else {// 如果不為空白則迴圈遍曆數組,對比每一個元素,返回第一個匹配的元素的索引indexfor (int i = this.size - 1; i >= 0; i--) {if (this.elementData[i].equals(o)) {return i;}}}// 否則返回-1return -1;}@Overridepublic Object[] subList(int fromIndex, int toIndex) {if (fromIndex > toIndex) {throw new IllegalArgumentException("您的開始下標與結束小標不正確: fromIndex = "+ fromIndex + "toIndex = " + toIndex);}Object[] newObjs = new Object[toIndex - fromIndex];int j = 0;for (int i = fromIndex; i <= toIndex; i++) {newObjs[j] = this.elementData[i];j++;}return newObjs;}/** * 判斷參數索引是否大於實際數組的大小 * * @param index */private void rangeCheck(int index) {if (index >= this.size) {throw new IllegalArgumentException("您的座標已超出數組大小: size = "+ this.size + "index = " + index);}}private void fastRemove(int index) {modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index + 1, elementData, index,numMoved);elementData[--size] = null;}public String toString() {this.trimToSize();StringBuffer str = new StringBuffer();str.append("[");for (int i = 0; i < this.elementData.length; i++) {if (i == this.elementData.length - 1) {str.append(this.elementData[i]);} else {str.append(this.elementData[i] + ",");}}str.append("]");return str.toString();}private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// Write out array lengths.writeInt(elementData.length);// Write out all elements in the proper order.for (int i = 0; i < size; i++)s.writeObject(elementData[i]);if (modCount != expectedModCount) {throw new ConcurrentModificationException();}}private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in size, and any hidden stuffs.defaultReadObject();// Read in array length and allocate arrayint arrayLength = s.readInt();Object[] a = elementData = new Object[arrayLength];// Read in all elements in the proper order.for (int i = 0; i < size; i++)a[i] = s.readObject();}public int getModCount() {return modCount;}}