Java基础集合-ArrayList源码分析

ArrayList是数组实现的一个动态数组,同样也支持随机访问,与普通数组相比,它的容量可以动态增长,且支持泛型。

ArrayList实现了List接口,实现了对数组的添加、删除、修改、遍历等操作。

ArrayList是非线程安全的集合,多线程环境下建议使用CopyOnWriteArrayList

内部类

内部类描述
ArrayListSpliterator可分隔的并行迭代器
Itr迭代器
ListItr双向迭代器
SubList子列表

属性

/**
 * 列表的初始大小
 */
private static final int DEFAULT_CAPACITY = 10;

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

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

/**
 * 存放元素的数组
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * 元素个数
 */
private int size;

构造

ArrayList支持构造一个空的集合,或者通过一个Collection转换为ArrayList,也可以指定初始容量来创建一个ArrayList

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

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // defend against c.toArray (incorrectly) not returning Object[]
        // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

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);
    }
}

ArrayList的添加、修改、删除操作

扩容机制

private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        // 当前数组已饱和,执行扩容
        elementData = grow();
    elementData[s] = e;
    size = s + 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;
    // 扩容为旧数组的1.5倍
    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);
}

根据源码分析可知,ArrayList在每次添加元素的时候检查数组是否饱和,如果饱和,则创建一个比旧数组容量大1.5倍的新数组,再把旧数组拷贝进新数组。

遍历

ArrayList支持五种元素遍历:

ArrayList<Integer> integers = new ArrayList<>();
IntStream.range(0, 100000).forEach(integers::add);


// 1.随机访问
for (int i = 0; i < integers.size(); i++);

// 2.增强for循环
for (Integer i : integers);

// 3.迭代器
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()){iterator.next();};

// 4.双向迭代器
ListIterator<Integer> listIterator = integers.listIterator();
while (listIterator.hasNext()){listIterator.next();};

// 5.Stream流
integers.forEach(x->{});

迭代并发修改

使用Iterator遍历集合元素时不支持通过集合对象修改该集合的长度,否则会抛出ConcurrentModificationException并发修改异常。

ArrayList内部类Itr就是一个Iterator:

private class Itr implements Iterator<E> {
    // 游标
    int cursor; 
    // cursor前一个位置
    int lastRet = -1; 
    // 获取Iterator对象时ArrayList对象的修改次数
    int expectedModCount = modCount;

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

    @SuppressWarnings("unchecked")
    public E next() {
        // 检查expectedModCount, modCount是否相等,否则抛出并发修改异常
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    // 检查修改次数
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

我们可以看到,Itr的expectedModCount在创建Itr对象的时候就已经确定,不能使用ArrayList对象做添加、删除操作,是因为这两个操作都会改变modCount变量,每次做迭代调用next()方法的时候都会检查modCount是否改变,如果改变,则会抛出异常。

如果在Iterator迭代时删除元素,必须使用Iterator提供的remove()方法,表示删除当前迭代的元素。

但是通过ArrayList对象对象元素做更新,执行set(int index, E element)不会有影响。

如果需要在迭代器中做添加、删除、修改,那么就要使用双向迭代器ListIterator,因为ListIterator不仅继承了Iterator,还实现了add(E e)set(E e)方法。

toArray()异常

ArrayList中存在两个重载方法toArray(),它们都是将ArrayList转化为数组,但是返回类型不一样,如果使用不当,可能会导致类型转换异常,因为Object[] toArray()方法的返回数组类型为Object,不能再向下转型成目标类型。

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

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

toArray(T[] a)需要一个泛型参数,用来确定转换后的数组类型:

ArrayList<Integer> integers = new ArrayList<>();
// 转换后的元素类型为Object
Object[] objects = integers.toArray();
// 指定类型
Integer[] integers1 = integers.toArray(new Integer[0]);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值