Java集合框架之二-------ArrayLIst源码剖析

以jdk1.8为例,如其他版本有不同,暂不考虑

//默认容量
    private static final int DEFAULT_CAPACITY = 10;

//共享空常量数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
//共享空常量数组(与EMPTY_ELEMENTDATA的区别在于第一个元素被加进来的时候,知道如何扩展)
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 

两者的区别在于第一个元素被加进来的时候,扩展方式的不同

在加入元素的时候,调用ensureCapacityInternal(size + 1)方法

此时如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,让minCapacity等于Math.max方法,其中方法如下

该方法求出最大值;

这就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA和EMPTY_ELEMENTDATA的区别

//存放数组的缓存容量,不可序列化,ArrayList底层是使用数组来实现的
transient Object[] elementData; 
//记录list中存放的元素个数
private int size;

接下来看一些构造器

//指定扩展容量的构造器,参数>0按照指定容量扩展数组,参数=0用空的常量数组对象EMPTY_ELEMENTDATA,
//参数<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() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

无参构造器是在什么时候将默认数组大小10设定到elementData里面的呐

构造一个初始容量为 10 的空列表,当我们使用无参构造器new一个对象时,底层数组就是直接用长度为10的空常量数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA进行实例化;这个在添加第一个元素时调用add(E)或者 add(int, E)时候就会调用下面方法

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;//扩容扩的太小,就等于minCapacity
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);// 扩的太大,大于输出最大值就取Integer.MAX_VALUE,否则等于最大值
        //将原来的数组中的元素复制扩展到大小为newCapacity的新数组中,并返回这个新数组
        elementData = Arrays.copyOf(elementData, newCapacity);
/*
public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
*/

这里涉及hugeCapacity方法,表示大于数组最大值就去Integer.MAX_VALUE,否则就取数组最大值

 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

 使用集合toArray返回object[],并赋值给elementData,如果collection长度不为零,判断toArray方法是否真的返回了Object[].class,如果没有就,使用Arrays.copyOf将elementData的副本拷贝为Object[].class类型,复制给elementData,如果为空,空的常量数组对象EMPTY_ELEMENTDATA赋给了elementData;

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

返回数组的浅拷贝(不包括元素本身)

public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }


//直接使用数组随机访问的特点
    public E get(int index) {
        rangeCheck(index);//有效性检查

        return elementData(index);
    }
//返回旧值,设置新值
    public E set(int index, E element) {
        rangeCheck(index);//有效性检查

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    
    public void add(int index, E element) {
        rangeCheckForAdd(index);
//添加修改次数,判断是否需要扩张
        ensureCapacityInternal(size + 1);  // Increments modCount!!
//移动元素以备插入数据
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

//移除指定位置的元素,
    public E remove(int index) {
        rangeCheck(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; // clear to let GC do its work

        return oldValue;
    }

下面方法使用移除指定对象

无论是指定对象o是否为null,都是在ArrayList中找到与此第一个相等的元素的位置,然后调用fastRemove(index)来进行移除;如果没有找打指定对象o的位置,则返回false,表示没有移除成功。

 public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

与remove基本没差,少了有效性检查以及没有返回删除的值

   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
    }

猜你喜欢

转载自blog.csdn.net/huangwei18351/article/details/81609509