ArrayList详解

ArrayList是Java中一个可变大小的数组,它实现了List接口。其内部通过elementData数组存储元素,初始容量为10。添加元素时,如果容量不足会按一定规则扩容,通常是1.5倍。删除和插入元素涉及数组的移动。
摘要由CSDN通过智能技术生成

简介:

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

ArrayList 继承了 AbstractList ,并实现了 List 接口。

属性:

成员变量:

    transient Object[] elementData; //集合底层数据操作的数组

    private int size; //集合的长度
    protected transient int modCount = 0;//修改的次数(父类的成员变量)

常量:

    private static final int DEFAULT_CAPACITY = 10;//集合的默认长度

    private static final Object[] EMPTY_ELEMENTDATA = {};//空数组,一般赋值使用

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//空数组

构造器:

public ArrayList():

将空数组复制个elementData,创建一个空集合,因此调用无参构造方法默认创建一个不占用内存空间的集合。

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

public ArrayList(int initialCapacity):

创建一个initialCapacity大小内存空间的集合,initialCapacity必须大于或等于0。

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

public ArrayList(Collection<? extends E> c):

将集合转换为数组。判断数组的长度是否大于0,如果大于0则判断参数c的类型是否为ArrayList,如果是直接赋值给elementData,如果不是则进行拷贝。底层用的是System.arraycopy。如果长度等于0则直接将空数组EMPTY_ELEMENTDATA赋值给elementData。

public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

方法:

add(E e):

调用add(e, elementData, size)。

public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

add(E e, Object[] elementData, int s):重点

将元素添加到size索引空间内。(并不是集合最后一个元素, 因为size并不是elementData最后一个元素的索引)

源码中,数组扩充有五种情况:

  1. elementData.length > 0: 将elementData的长度扩充为10,并且将添加的值存入到索引0的空间内;

  1. elementData.length <= 10: 直接将数据添加到elementData中;

  1. elementData.length > 10:将elementData的长度扩大到1.5倍,如果扩充的长度还是小于最小容量minCapacity,直接将elementData的数据扩容到minCapacity长度,并且将原数据拷贝到elementData中;

  1. elementData.length > MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8) : 将elementData的数组长度扩容到Integer.MAX_VALUE,并且将源数据拷贝到elementData中;

  1. elementData.length > Integer.MAX_VALUE : 报错;

总结:一个空集合第一次扩充的容量为10,当需要的容量大于10之后就是每次扩容当前集合底层数组长度的1.5倍,如果扩容的长度小于需要的长度,则直接扩容到需要的长度。集合最大长度为Integer.MAX_VALUE。

private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();//扩充ArrayList数组
        elementData[s] = e;
        size = s + 1;
    }

添加一个元素调用的所有方法:


    private Object[] grow() {
        return grow(size + 1);
    }


    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }


    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }


    //集合达到极限的处理 
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }

add(int index, E element):

将存储数据的数组进行扩容将元素添加到index索引的内存空间内,并且将index索引后面的所有元素拷贝到 index+1,index+2......索引空间内。

public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();

        //拷贝  其他的就是数组扩容  可以看上方解析 
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

public E remove(int index):

首先判断要删除的索引是否越界。然后将index索引后面的值都赋值给前面,最后一个索引的值赋值为null。类似于 elementData[index] = elementData[index + 1];elementData[index + 1] = elementData[index + 2];.....最后elementData[--size] = null。

    public E remove(int index) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }

    private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }

boolean remove(Object o):

删除集合中第一个o元素。底层就是一个for循环遍历数组elementData,如果找到了则结束for循环,如果没找到则返回false。找到索引之后也是运行的fastRemove(Object[] es, int i)方法。

    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
        found: {
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
                        break found;
            } else {
                for (; i < size; i++)
                    if (o.equals(es[i]))
                        break found;
            }
            return false;
        }
        fastRemove(es, i);
        return true;
    }

    private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值