ArrayList类

ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List)

实现的接口和继承的类

函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类,它的容量是自动增长的。ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问(比使用迭代器访问更快),该接口只是一个标记接口,也无法强制用户做什么,实现了Cloneable接口,能被克隆。它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作

ArrayList定义类中俩个重要属性

继承的父类AbstractList有个重要的属性protected transient int modCount = 0;从结构上修改 、此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。
在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列表元素数量发生改变)了,主要在多线程环境下需要使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。

transient Object[] elementData; // non-private to simplify nested class access
private int size;

elementData保存容器的元素,size指容器中元素的个数。

三种构造方法

//用户定义了初始大小为initialCapacity的构造方法 
 public ArrayList(int initialCapacity) {} 
 //无参的构造方法,默认容量是10 
 public ArrayList() {} 
 //初始化一个包含集合c的容器,大小也等于c的大小 
 public ArrayList(Collection

元素存储

ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

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

每次添加元素都要检查容器大小是否足够,如果元素数组是空,则容器为默认大小10,如果且容器大小不够,则把容器大小增加为原来的1.5倍,如果还是不够,新容器大小为新加上进来元素或者集合的大小.
这里有个问题hugeCapacity(int minCapacity);MAX_ARRAY_SIZE比Integer.MAX_VALUE小8.文档解释是一些虚拟机在数组中保留了一些头字节,分配更多的空间可能导致内存溢出。也有解释是数组自己用了8个字节存储大小2,147,483,648,所以存储容量为2的31次方-8.

元素读取

// 返回此列表中指定位置上的元素。  
 public E get(int index) {  
    RangeCheck(index);  
    return (E) elementData[index];  
  }

元素删除

// 移除此列表中指定位置上的元素。返回移除的元素
public E remove(int index) { }
// 移除此列表中首次出现的指定元素(如果存在)。这是因为ArrayList中允许存放重复的元素。
public boolean remove(Object o) { }

总结

当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。