Java集合·02·ArrayList详解

一、概述

是一个数组队列,相当于动态数组。与一般数组不同的是,它的容量可以动态改变。

继承自AbstractList,实现了List、RandomAccess、java.io.Serializable、Clone接口。

Collection

表示高度抽象的集合接口,它包含了集合的基本操作:添加、删除、清空、遍历(读取)、是否为空、获取大小、是否保护某元素等等。

List

继承自Collection,表示有序集合,每个元素都有一个索引。添加了“添加、删除、获取、修改指定位置的元素”、“获取List中的子队列”等API接口。

CollectionAbstract

一个抽象类,它实现了Collection中除iterator()和size()之外的函数。

AbstractList

继承于AbstractCollection,并且实现List接口的抽象类。它实现了List中除size()、get(int location)之外的函数。

二、数据结构

数组,默认容量大小为10,类型为Object[],可动态扩展

private Object[] elementData; //用于存储数据
private int size;             //用于记录当前有效数据数量

三、特点

  • 有序
  • 容量可变
  • value可以为null

四、实现要点

1. 动态扩容/减少容量原理

ensureCapacity,扩展数组容量,每次尝试扩展1/2,如果仍然小于目标capacity,则直接设置为目标capacity。

调用时机:添加数据时,add(E e)add(int index, E e)addAll(Collection c)addAll(int index, Collection c) 方法会先调用ensureCapacity(newSize)保证数组大小足够。

public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != EMPTY_ELEMENTDATA)
        // any size if real element table
        ? 0
        // larger than default for empty table. It's already supposed to be
        // at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        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;
    }

trimToSize,public方法,用于减少ArrayList所占内存。

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = Arrays.copyOf(elementData, size);
    }
}

2. Iterato实现原理

Iterator中记录两个序号,当前元素序号(next()方法返回元素序号)cursor,上次指向元素序号lastRef

Iterator方法:

  • next() 更新cursor和lastRef序号,lastRef=cursor,cursor+1,返回lastRef序号元素

  • hasNext() cursor < limit

  • remove() cursor指向lastRef,删除lastRef指向元素,并将lastRef置为-1

    lastRef置为-1,保证多次调用lastRef相关方法不会影响到现有元素,直接抛出异常

ListIterator方法:

  • previous() 更新cursor和lastRef序号,cursor-1,lastRef=cursor,返回lastRef序号元素
  • hasPrevious() cursor != 0;
  • set() 直接设置lastRet元素
  • add() cursor位置插入元素,cursor+1,lastRef=-1

3. 线程安全性

对ArrayList的操作都是非线程安全的。如果需要在多线程环境下进行操作,可以使用

  • List list = Collections.synchronizedList(new ArrayList());获取线程安全的ArrayList。
  • 使用CopyOnWriteArrayList

Collections.synchronizedList()通过重写ArrayList相关方法,添加一个互斥量mutex,方法调用之前都要尝试先去获取mutex

4. SubList

SubList 依赖parent的数据结构,根据parent的数据结构的不同SubList实现不一致

原理:

依然是使用原列表,内部维护一个指向parentList的引用。对SubList的操作会直接影响到parentList。

区别:

每次操作前都要检查本地modCount和原列表modCount,可能抛出ConcurrentModificationException。

使用场景:

使用 subList 处理局部列表。获取一堆数据后,需要删除某段数据。例如,有一个列表存在 1000 条记录,我们需要删除 100-200 位置处的数据:

list1.subList(100, 200).clear();

五、访问方式

ArrayList可以通过三种方式进行访问

Iterator,通过迭代器去遍历

Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

RandomAccess,随机访问,通过索引值去遍历

Integer value = null;
int size = list.size();
for (int i=0; i

foreach循环遍历

Integer value = null;
for (Integer integ:list) {
    value = integ;
}

你可能感兴趣的:(Java集合·02·ArrayList详解)