JAVA容器之-ArrayList

/** 考虑到Vector和ArrayList没有什么本质的区别,除了Vector可以指定扩容的大小和默认的两倍扩容策略和各种同步的方法外,基本的操作没什么质的不同,因此就不讨论Vector了*/
package test;

import java.util.*;

/**
 * Created by wenge on 2018/6/11.
 */
public class LArrayList<E> {
    transient Object[] elementData;
    private int size;
    private static final int DEFAULT_SIZE = 10;
    private static final Object[] EMPTY_ELEMENT = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 常规的初始化列表,其elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     */
    public LArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 根据初始化容量初始化列表
     *
     * @param initialCapacity 初始化容量,要考虑鲁棒性
     */
    public LArrayList(int initialCapacity) {
        //如果initialSize > 0才可以安全初始化
        if (initialCapacity > 0) {
            elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            elementData = EMPTY_ELEMENT;    //如果初始容量为0,那么就将elementData初始化为空
        } else {
            throw new IllegalArgumentException("Illegal Capacity : " + initialCapacity);
        }
    }

    /**
     * 根据集合来初始化
     * <p>
     * 这里有一个bug,就是将集合元素赋值可能会有一点小问题
     * 不是所有的Collection的toArray方法都能返回真正意义上的Object[]
     * 有些仅仅返回的是这种类型的引用,但是实际上里面的元素类型是具体的。
     * 如:<code>Arrays.asList()</code>返回的Arrays$ArrayList的toArray里面的元素是具体类型
     * objs.getClass()可能不是Object[].class
     * 而:ArrayList的toArray则返回的是真正意义上的Object[]数组
     *
     * @param c 集合
     */
    public LArrayList(Collection<? extends E> c) {
        elementData = c.toArray();      //先把集合转换成为数组,但是有可能转换成为的数组不能存放Object类型
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class) {
                elementData = Arrays.copyOf(elementData, size, Object[].class);
            }
        } else {
            elementData = EMPTY_ELEMENT;
        }
    }

    /**
     * 当你想添加一个元素的时候,首先要看容量是否还足够
     * 如果list刚刚创建,则将最小需要的容量改为10
     * 根据最小需要的容量去看是否要扩容
     * 如果当前容量足够,则不需要扩容
     * 否则需要扩容,扩容的策略是将elementData的容量定位原先的1.5倍
     * 如果1.5倍的容量还是不够,那么就扩容成为最小需要的容量
     * 如果新的容量溢出了,则要考虑创建一个合适的容量,如果最少需要的容量超出了Integer的最大值
     * 则抛出异常,否则如果需要的容量>数组的最大容量,那么就用Integer的最大值,否则就用最大数组的容量
     *
     * @param e 需要添加的元素
     * @return
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);       //看是否要扩容
        elementData[size++] = e;
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {      //说明这个list才刚刚创建
            minCapacity = Math.max(minCapacity, DEFAULT_SIZE);     //则想将容量最少扩展为10
        }
        ensureExplicitCapacity(minCapacity);    //根据最少需要的容量去扩容
    }

    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0)       //容量不够就扩容
            grow(minCapacity);
    }

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);         //默认扩容1.5倍
        if (newCapacity - minCapacity < 0)      //1.5倍还不够的化就用minCapacity
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)       //容量超过最大容量
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) //也就是说超出了int的取值范围
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

    public E remove(int index) {
        rangeCheck(index);
        E oldEle = (E) elementData[index];
        int numToMove = size - index - 1;
        if (numToMove > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, numToMove);
        }
        elementData[--size] = null;     //垃圾回收
        return oldEle;
    }

    private void rangeCheck(int index) {        //这里之所不考虑负数是因为数组的索引不能为负数,否则会抛出异常
        if (index > size - 1)
            throw new IndexOutOfBoundsException("Index : " + index + ", Size : " + size);
    }

    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean contains(Object o) {         //contains基于迭代器
        Iterator it = Arrays.asList(toArray()).iterator();
        if (o == null) {
            while (it.hasNext())
                if (null == it.next())
                    return true;
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return true;
        }
        return false;
    }

    /**
     * 移除底部采用的是快慢指针,用不存在的元素替换存在的元素
     *
     * @param c 移除的集合
     * @return
     */
    public boolean removeAll(Collection<E> c) {
        if (c == null)
            throw new IllegalArgumentException("参数不能为空");
        return batchRemove(c, false);
    }

    private boolean batchRemove(Collection<E> c, boolean complete) {        //批量删除基于双指针压缩
        final Object[] elementData = this.elementData;
        int fast, slow;   //w为慢指针,r为快指针
        for (slow = 0, fast = 0; fast < size; fast++) {
            if (c.contains(elementData[fast]) == complete) {
                elementData[slow++] = elementData[fast];
            }
        }
        for (int i = slow; i < size; i++) {
            elementData[i] = null;     //help gc
        }
        size = slow;
        this.elementData = Arrays.copyOf(this.elementData, size);
        return true;
    }

    public String toString() {
        if (size == 0) {
            return "[]";
        }
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < size; i++) {
            sb.append(elementData[i] + ", ");
        }
        String s = sb.substring(0, sb.length() - 2);
        sb = new StringBuilder(s);
        sb.append("]");
        return sb.toString();
    }

    /**
     * 标准迭代器,list还有一个内部实现的listIterator,可以查找前后元素,并且可以添加元素
     */
    private class Itr implements Iterator<E> {
        private int cursor;
        private int lastReturn = -1;        //表示最后返回的一个元素的索引,用于恢复删除

        @Override
        public boolean hasNext() {
            return cursor != size;
        }

        @Override
        public E next() {       //next之后,游标指向下一个
            lastReturn = cursor;
            cursor = cursor + 1;
            return (E) elementData[lastReturn]; //返回当前元素
        }

        @Override
        public void remove() {      //移除元素的时候要把游标归位,也就是归位到上一次返回元素的下标
            LArrayList.this.remove(lastReturn);
            cursor = lastReturn;
            lastReturn = -1;
        }
    }
    public Iterator<E> iterate() {
        return new Itr();
    }
    public void clear() {
        // help gc
        for(int i = 0; i < size; i++) {
            elementData[i] = null;
        }
        size = 0;
    }
}

猜你喜欢

转载自blog.csdn.net/lanyage_csdn/article/details/80651979