自己理解的java.util.ArrayList(二)实现类

2019-04-14 12:18发布

package myList; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Iterator; /** * 一个模拟arraylist的简单的集合类 * * @author 姜侠 * * @param */ public class MyArrayList implements MyList, 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); } } @Override public int size() { return this.size; } @Override public boolean isEmpty() { return this.size == 0; } @Override public boolean contains(Object obj) { return indexOf(obj) >= 0; } @Override public Iterator iterator() { return null; } @Override public Object[] toArray() { return java.util.Arrays.copyOf(elementData, size); } @Override public boolean add(E e) { // 先判断是否进行扩充 this.ensureCapacity(this.size + 1); // 添加数据 this.elementData[size++] = e; return true; } @Override public 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; } @Override public boolean containsAll(MyList 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; } @Override public boolean removeAll(MyList list) { for (int i = 0; i < list.size(); i++) { if (this.contains(list.get(i))) { this.remove(list.get(i)); } } return true; } @Override public boolean addAll(MyList list) { int numNew = list.size(); // 是否扩容 ensureCapacity(size + numNew); // Increments modCount // 元素右移 System.arraycopy(list.toArray(), 0, elementData, size, numNew); // 更新数组实际大小 size += numNew; return numNew != 0; } @Override public boolean addAll(int index, MyList list) { // 判断索引是否符合要求 if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); int numNew = list.size(); // 是否扩容 ensureCapacity(size + numNew); // Increments modCount int 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; } @Override public boolean retainAll(MyList list) { // 判断参数数组是否为空,如果为空则清空elementData if (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; } @Override public void clear() { // 重构数组次数+1 modCount++; // 遍历数组,就所有的元素设为空 for (int i = 0; i < size; i++) elementData[i] = null; // 数组实际大小为0 size = 0; } @Override public E get(int index) { rangeCheck(index); return (E) elementData[index]; } @Override public E set(int index, E element) { rangeCheck(index); Object oldElement = this.elementData[index]; this.elementData[index] = element; return (E) oldElement; } @Override public 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++; } @Override public 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 work return oldValue; } @Override public int indexOf(Object o) { // 判断对象是否为空 // 如果为空则循环遍历数组,对比那个元素是空,返回第一个匹配的元素的索引index if (o == null) { for (int i = 0; i < this.size; i++) { if (this.elementData[i] == null) { return i; } } } else { // 如果不为空则循环遍历数组,对比每一个元素,返回第一个匹配的元素的索引index for (int i = 0; i < this.size; i++) { if (this.elementData[i].equals(o)) { return i; } } } // 否则返回-1 return -1; } @Override public int lastIndexOf(Object o) { // 判断对象是否为空 // 如果为空则循环遍历数组,对比那个元素是空,返回第一个匹配的元素的索引index if (o == null) { for (int i = this.size - 1; i >= 0; i--) { if (this.elementData[i] == null) { return i; } } } else { // 如果不为空则循环遍历数组,对比每一个元素,返回第一个匹配的元素的索引index for (int i = this.size - 1; i >= 0; i--) { if (this.elementData[i].equals(o)) { return i; } } } // 否则返回-1 return -1; } @Override public 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 stuff int expectedModCount = modCount; s.defaultWriteObject(); // Write out array length s.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 stuff s.defaultReadObject(); // Read in array length and allocate array int 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; } }