JDK1.8源码阅读之java.util.ArrayList

JDK1.8源码阅读之java.util.ArrayList

构造器方法

无参构造器

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access

// 将elementData数组初始化为空。
// 这里是惰性扩容,当要往数组中插入元素时,才会初始化扩容成默认长度10。
public ArrayList() {
   this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

有参构造器

private static final Object[] 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的方法
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

add方法

步骤:

  1. 将插入的基础数据类型进行包装,比如int转换成Integer
    // 这里的cache是一个数组,int类型的范围[-128,127]
    // cache[0]=-128
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
  2. 插入数据前需要确保数组容量充足
    private int size;
    transient Object[] elementData; // non-private to simplify nested class access
    
    // 通过ensureCapacityInternal方法检查容量是否充足,如果不足就进行扩容
    // size则是ArrayList对象维护的一个成员变量
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    // 在某个索引处添加元素。
    // 将index以及其后的所有元素向后移动一格
    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++;
    }
    
    // elementData 则是ArrayList对象的数据
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
  3. 计算需要的容量
    private static final int DEFAULT_CAPACITY = 10;
    
    // 这个方法同时传入了elementData数组与minCapacity,考虑了数组是空的情况。
    // 如果ArrayList才刚初始化,没有插入过数据,会直接扩容成DEFAULT_CAPACITY,也就是10
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
           if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
               return Math.max(DEFAULT_CAPACITY, minCapacity);
           }
           return minCapacity;
       }
    
  4. 检查是否需要扩容
    protected transient int modCount = 0;
    
    // modeCount是在每次修改ListArray都需要+1的,目的是为了在迭代器中确保其不被改动
    // 逻辑:如果当前需要的最小容量小于elementData数组的长度就不需要扩容了
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
  5. 扩容
    // 每次扩容为原容量的1.5倍,并重开一个这么大容量的数组,将数据拷贝进去。
    // 数组地址与原来的不同了
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 考虑到初始化的问题,未插入过元素的数组的长度为0
        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);
    }
    
    继续执行步骤2中的size++,并将元素放入到数组中,返回true

remove方法

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

// 通过元素remove
// 遍历查询到该元素,之后执行与上一个remove相似的操作。但是这里就不需要check索引了
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;
}
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
}

contians方法与indexOf方法

// 返回的是boolean,是否含有某个元素
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

// 循环遍历数组,如果有相同的就返回索引
public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

// 倒序遍历
public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

clone方法

// 浅拷贝,元素本身并不会被拷贝。因此如果数组元素时对象,且如果在v中改变元素,原数组内的元素也会发生改变
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);
    }
}

trimToSize方法

// 为了节省空间,可以让数组变成适合他的大小。
// 比如初始化了10,但是只用了5的情况。
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

最大容量

// 因为虚拟机中会有头部信息,因此最大容量是Integer.MAX_VALUE-8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值