集合

ArrayList源码分析底层原理

public class ArrayList<E> implements List<E> {

    /**
     * 实际个数
     */
    private int size;

    /**
     * Object数组对象  arrayList底层就是这个实现的   transient:不被序列化
     */
    transient Object[] elementData;

    /**
     * 用于无参构造初始化数组
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 空数组实例
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 默认容器大小10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 数组最多容量大小=整数最大值-8
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 修改次数
     * 每当会修改表的操作执行时,都将此属性自增1。使用者只需要前后对比该字段就知道中间这段时间表是否被修改。
     * 用于使用迭代器迭的时候快速定位失败机制
     */
    protected transient int modCount = 0;

    /**
     * 无参构造  初始化空数组
     */
    public ArrayList() {
        elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 有参构造  初始化数组并且设置容器的容量大小
     *
     * @param initialCapacity 初始化容量大小
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            elementData = new Object[initialCapacity];// 如果用的时候参数>0,则开辟对象数组
        } else if (initialCapacity == 0) {
            elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("参数有误,initialCapacity:" + initialCapacity);
        }
    }


    @Override
    public int size() {
        return size;
    }

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

    @Override
    public boolean contains(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elementData(i) == null) {
                    return true;
                }
            }
            return false;
        }
        for (int i = 0; i < size; i++) {
            if (o.equals(elementData(i))) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }


    private void ensureCapacityInternal(int minCapacity) {
        /**
         * 容器为空则重新给minCapacity赋值
         */
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //取最大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        /**
         * 如果minCapacity-数组容量>0 此时需要进行扩容操作
         */
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity);
        }

    }

    /**
     * 扩容操作
     *
     * @param minCapacity 所需最小容量
     */
    private void grow(int minCapacity) {
        //原来容量大小
        int oldCapacity = elementData.length;
        //新容量大小  在原有容量基础之上扩容50%   右移: >>1相对于除2
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        //如果扩容之后的容量-最小容量大小小于0  则新容量大小=最小容量大小
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        //如果newCapacity-int最大值-8>0说明超过最大限制
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }
        //将原来数据复制到新的容器  此时容器扩容结束
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    @Override
    public boolean remove(Object o) {
        //判断删除对象是否为null  因为集合中是允许存null
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elementData(i) == null) {
                    fastRemove(i);
                    return true;
                }
            }
            return false;
        }
        for (int i = 0; i < size; i++) {
            if (o.equals(elementData(i))) {
                fastRemove(i);
                return true;
            }
        }
        return false;
    }

    /**
     * 改方法跳过下标检查删除  应用场景到remove(Object o)方法里面
     *
     * @param 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;
    }

    @Override
    public void clear() {
        modCount++;
        //遍历元素 然后根据下标置空
        for (int i = 0; i < size; i++) {
            elementData[i] = null;
        }
        //实际个数归零
        size = 0;
    }

    @Override
    public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }

    /**
     * 检查下标是否越界
     *
     * @param index
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new ArrayIndexOutOfBoundsException("下标越界,index:" + index);
    }

    /**
     * 根据下标获取元素
     *
     * @param index
     * @return
     */
    private E elementData(int index) {
        return (E) elementData[index];
    }

    @Override
    public E set(int index, E element) {
        rangeCheck(index);
        //获取原来的值  将其返回
        E oldValue = elementData(index);
        //根据下标覆盖之前的值
        elementData[index] = element;
        return oldValue;
    }

    @Override
    public void add(int index, E element) {
        rangeCheck(index);
        ensureCapacityInternal(size + 1);
        //计算移动长度  因为这个是根据index来新增元素的  所以>=index的所有元素都往后面移动  这边的长度是不需要-1了
        int moveNum = size - index;
        System.arraycopy(elementData, index, elementData, index + 1, moveNum);
        elementData[index] = element;
        size++;
    }

    @Override
    public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        //计算移动的长度  实际个数-index然后再减1
        int numMoved = size - index - 1;
        //如果要移动长度大于0  则使用下面方法进行数组复制操作  否则直接将容器中--size置空
        if (numMoved > 0) {
            /**
             * src:源数组;
             * srcPos:源数组要复制的起始位置;
             * dest:目的数组;
             * destPos:目的数组放置的起始位置;
             * length:复制的长度。
             */
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        }
        //最后一个元素置空
        elementData[--size] = null;
        return oldValue;
    }

    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<Integer>();
        for (int i = 0; i < 50; i++) {
            nums.add(i + 1);
        }
        for (int i = 0; i < nums.size(); i++) {
            System.out.print(nums.get(i) + "\t");
        }
        System.out.println("\n删除下标9");
        nums.remove(9);
        for (int i = 0; i < nums.size(); i++) {
            System.out.print(nums.get(i) + "\t");
        }
        System.out.println("\n在下标9的位置新增元素10");
        nums.add(9, 10);
        for (int i = 0; i < nums.size(); i++) {
            System.out.print(nums.get(i) + "\t");
        }
        System.out.println("\n修改下标9,将值改为666");
        nums.set(49, 666);
        for (int i = 0; i < nums.size(); i++) {
            System.out.print(nums.get(i) + "\t");
        }
        System.out.println("\n是否包含元素666--->isFlag:" + nums.contains(666));
        System.out.println("size:" + nums.size());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值