ArrayList源码研究

来源:互联网 发布:linux telnet端口 编辑:程序博客网 时间:2024/06/10 02:41
package List;import java.util.Arrays;import java.util.Collection;/*有序、元素可重复、插入慢、 索引快*/public class MyArrayList<E> {private static final int DEFAULT_CAPACITY = 4;private static final int MAX_CAPACITY = 6;// 只允许扩容一次,空参的话是两次private Object[] EMPTY_ELEMENTDATA = {};private Object[] elementData;private int size;// 这个跟数组的length属性完全不一样,这个是有几个元素返回size个// 而数组的length属性是返回数组的实际长度int count = 0;/* 空参构造函数,把空数组给真实数组 */public MyArrayList() {super();elementData = EMPTY_ELEMENTDATA;}/* 参数是Collection,证明数组中已经要存储c.size个元素 */public MyArrayList(Collection<? extends E> c) {super();elementData = c.toArray();size = c.size();}/* 自定义数组容量大小 */public MyArrayList(int initCapacity) {super();elementData = new Object[initCapacity];}/* 添加方法 */public boolean add(E e) {ensureEnoughSize(size + 1);// 将当前的size+1作为参数去看看有没有超过此时的数组长度elementData[size++] = e;// 如果是超过了数组长度,扩容后添加这个e. 如果没有超过数组长度,那么直接添加进数组return true;}/* 在指定位置添加 */public void add(int index, E element) {rangeCheckForAdd(index);// 只允许在[0,size]之间插入。ensureEnoughSize(size + 1);// 保证数组有充足的空间// 将指定索引位置右端元素右移 ,// 如果是在0位置插入的话,从原数组的0角标开始,复制size个到新数组的从1开始,腾出0角标位置System.arraycopy(elementData, index, elementData, index + 1, size- index);elementData[index] = element;// 在腾出的地方添加元素,在最后一个位置添加的时候不用移动数组size++;}/* 输出所有,包括null */public void show() {for (int i = 0; i < elementData.length; i++) {System.out.print(" " + elementData[i]);}System.out.println();}/* 输出所有但不带上最后面扩容后存在的null */public void showActually() {for (int i = 0; i < size; i++) {System.out.print(" " + elementData[i]);}System.out.println();}/* 清空所有 */public void clear() {for (int i = 0; i < size; i++) {elementData[i] = null;}size = 0;}/* 查找是否存在相关的元素 */public boolean contains(E e) {return indexOf(e) >= 0;}/* 返回第一次与指定相同的元素的角标 */public int indexOf(E e) {if (null == e) {for (int i = 0; i < size; i++) {if (elementData[i] == e) {return i;}}} else {for (int i = 0; i < size; i++) {if (elementData[i] == e) {return i;}}}return -1;}/* 查询最后一次出现此元素的角标,从后往前遍历,nice! *//* 用Object是因为比较的是对象,而==表示内存地址也是一样,equals是内容一样也可以 */public int lastIndexOf(Object obj) {if (obj == null) {for (int i = 0; i < size; i++) {if (elementData[i] == null)return i;}} else {for (int i = size - 1; i >= 0; i--) {if (obj.equals(elementData[i]))return i;}}return -1;}/* 返回指定位置上的元素 */@SuppressWarnings("unchecked")public E get(int index) {rangeCheck(index);return (E) elementData[index];}/* 判断是否为空,别自作聪明说还用三目运算符,size==0?true:false; */public boolean isEmpty() {return size == 0;}/* 删除指定角标上的元素 */public E remove(int index) {rangeCheck(index);E oldValue = this.get(index);// 这里get里面也有检查范围,要不要写上面的这一句呢?int numMoved = size - index - 1;// 右边准备向左移动的元素的个数// 从角标右边的第一个开始算,全部左移一位,还剩数组的最后一个元素System.arraycopy(elementData, index + 1, elementData, index, numMoved);elementData[--size] = null;// 实际个数减一,数组最后一位置空return oldValue;}/* 移除此列表中首次出现的指定元素(如果存在) */public boolean remove(E e) {int index = indexOf(e);//先根据元素去查角标,没查到就返回假if (index < 0){return false;//没查到也删不成}remove(index);//在数组中查询到了此元素,调用删除角标的remove方法。return true;}/*移除指定区间的元素*/public void removeRange(int fromIndex,int toIndex){rangeCheck(fromIndex);rangeCheck(toIndex);int numMove = toIndex - fromIndex;System.arraycopy(elementData, toIndex, elementData, fromIndex, numMove);}private void rangeCheck(int index) {if (index >= size || index < 0)throw new IndexOutOfBoundsException("角标越觉");}private void rangeCheckForAdd(int index) {if (index > size || index < 0)throw new IndexOutOfBoundsException("角标越觉");}/* 将size+1作为参数,表示现在要想添加成功,数组此次必须的最小容量 */private void ensureEnoughSize(int minCapacity) {/* 空参的构造器的情况,将默认容量作为最小容量,第一次必定扩容 */if (elementData == EMPTY_ELEMENTDATA) {// 如果是空的数组,那么就把默认大小的值作为 数组此次必须的最小容量minCapacity = Math.max(minCapacity, DEFAULT_CAPACITY);}ensureExplicitCapacity(minCapacity);// 扩容否?}/* 如果必须的长度已经超越了现在数组的长度,那么就要扩容 */private void ensureExplicitCapacity(int minCapacity) {if (minCapacity > elementData.length) {grow(minCapacity);}}/*核心:扩容*/private void grow(int minCapacity) {System.out.println("扩容执行" + (++count) + "次");int oldCapacity = elementData.length;// 空参的话,旧长度是0,扩充后还是0int newCapacity = oldCapacity + (oldCapacity >> 1);// 扩充为1.5倍,一定要加括号!,不然根本加不上!Debug亲测!if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;// 扩充1.5倍也并没有什么卵用的话,那就用这个:数组此次必须的最小容量,但是有最大容量的限制}if (newCapacity - MAX_CAPACITY > 0) {try {throw new Exception("数组长度超过允许的最大长度");} catch (Exception e) {e.printStackTrace();return;}}elementData = Arrays.copyOf(elementData, newCapacity);// 返回扩容后的数组}/*返回当前元素的个数*/public int size() {return size;}/*为了弄出在内存中的创建的数组的长度*/public Object[] getElementData() {return elementData;}}

原创粉丝点击