源码之ArrayList和Vector

父类介绍

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}

说明:java

  • 继承AbstractList,实现List接口,提供了add、remove、indexOf、get等相关方法
  • 实现RandomAccess接口,提供了随机访问功能。在ArrayList中,咱们便可以经过元素的序号快速获取元素对象;这就是快速随机访问。RandomAccess接口是一个标记接口,它并未定义方法。其目的是用于指示实现类具备随机访问特性,在遍历时使用下标访问较迭代器更快
  • 实现Cloneable,提供了克隆方法
  • 实现Serializable,支持序列化

属性

默认属性

//数组默认大小10
private static final int DEFAULT_CAPACITY = 10;
//默认数据 空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

其余属性

数据

transient Object[] elementData;

这里用transient修饰,是为了防止自动序列化。缘由:数组

因为 ArrayList 是基于动态数组实现的,因此并非全部的空间都被使用。所以使用了 transient 修饰,能够防止被自动序列化。

因此,ArrayList也自定义了序列化和反序列化方法,只序列化当前存放的数据安全

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        int expectedModCount = modCount;
        s.defaultWriteObject();
        s.writeInt(size);
        // 这里只序列化已经有的数据,并非全部空间都序列化
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;
        s.defaultReadObject();
        s.readInt(); 

        if (size > 0) {
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // 反序列化,读取数据
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

大小

private int size;//ArrayList的数组大小

修改次数与快速失败

//修改次数 父类AbstractList全部
protected transient int modCount = 0;
//指望修改次数 父类AbstractList的内部类Itr全部
int expectedModCount = modCount;

说明多线程

ArrayList的全部关于结构变化的操做(add、remove、addAll、removeRange和clear),都会让modCount++

而在私有内部类迭代器Itr中定义了变量expectedModCount和checkForComodification方法
private class Itr implements Iterator<E> {
    //指望的修改次数
    int expectedModCount = modCount;
    //修改检查方法()
    final void checkForComodification() {
        //若是修改数和指望修改数不一致,抛出异常
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

好处:快速失败dom

若是在多线程环境中,使用迭代器操做ArrayList的时候可能形成修改次数不一致,每次迭代器更新数据前检查,来保证数据安全和一致,若是不一致能让迭代快速失败

添加元素

add(obj) 在数组尾部添加

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 扩容(若是必要),而且 modCount++
        elementData[size++] = e;//数组尾部添加元素
        return true;
    }

add(index, obj) 复制数组,效率不好

//在指定位置添加元素
public void add(int index, E element) {
    rangeCheckForAdd(index);//校验index是否大于数组长度或者小于0

    ensureCapacityInternal(size + 1);  // 扩容(若是必要),而且 modCount++
    //对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;//将插入的值放到指定位置index
    size++;//将 size + 1 
}

添加集合 addAll(),效率较差

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);
		//数组复制和移动
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

修改元素 set

在指定位置设置新的值,并返回旧值this

public E set(int index, E element) {
    rangeCheck(index);//检查index是否超过数组大小

    E oldValue = elementData(index);//获取到以前的值
    elementData[index] = element;//设置新值
    return oldValue;//返回以前的值
}

扩容

//扩容检测
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // 当数组容量不足,调用grow进行扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;//获取当前容量大小
    int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量=当前容量的1.5倍
    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);
}

快速随机访问 get

public E get(int index) {
    rangeCheck(index);//检查index是否超过数组大小
    return elementData(index);//返回数组指定位置的元素
}

移除元素 remove 效率较差

给定位置移除

移除指定位置元素,返回被移除位置上的元素值线程

public E remove(int index) {
    rangeCheck(index);//index合法检查
    modCount++;//修改次数++
    E oldValue = elementData(index);//获取旧值
    int numMoved = size - index - 1;//计算该位置后面的数组大小
    if (numMoved > 0)
        //从新移动数组
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; //清除数组,让gc收集
    return oldValue;
}

给定元素值移除

public boolean remove(Object o) {
        if (o == null) {//移除null值
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {//移除非null值
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
	
	//快速移除,数组复制和移动
	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; // clear to let GC do its work
    }

Vector

线程安全code

Vector相似于ArrayList,是一个动态数组,只是它是一个线程安全的数组容器。它的add、set、remove方法都是用synchronized来修饰的。

扩容对象

//Vector的扩容,不是按1.5倍,二是1倍
private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //按原来的1倍扩容
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
相关文章
相关标签/搜索