ArrayList源码分析

 首先Array实现的接口

RandomAccess:接口RandomAccess中内容是空的,只是作为标记用。比如List下的ArrayList和LinkedList。其中ArrayList实现了RandomAccess。而LinkedList没有。我们可以利用instanceof来判断哪一个是实现了RandomAccess。分辨出两个集合。其中ArrayList使用for循环遍历快,而LinkedList使用迭代器快。那么通过分辨,不同的集合使用不同的遍历方式。

如下例子

ArrayList

LinkedList

Cloneable:克隆接口,肯定要重写clone()方法

java.io.Serializable:序列化接口

一 基础变量

//数组默认初始容量为10
private static final int DEFAULT_CAPACITY = 10;

//长度为0的空数组
private static final Object[] EMPTY_ELEMENTDATA = {};

//长度为0的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//记录list的逻辑长度(存放元素的个数)
private int size;

//集合存储数据的容器(数组)
transient Object[] elementData; 

           transient干嘛用的?当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。

      因为ArrayList不能序列化和反序列化吗?肯定不是,是因为elementData里面不是所有的元素都有数据,因为容量的问题,elementData里面有一些元素是空的,这种是没有必要序列化的。ArrayList的序列化和反序列化依赖writeObject和readObject方法来实现。可以避免序列化空的元素。

二 无参构造方法

初始化的时候讲空数组赋值给数据容器

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

三 add方法

public boolean add(E e) {
   ensureCapacityInternal(size + 1);  // Increments modCount!!
   //给缓冲器赋值的同时,记录元素的个数
   elementData[size++] = e;
   此方法是有返回值的
   return true;
}

private void ensureCapacityInternal(int minCapacity) {
    //第一次添加元素时 minCapacity=1
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //ArrayList会在第一次添加元素的时候设置数组缓冲器的初始大小为10.
        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 static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

//扩容方法
private void grow(int minCapacity) {
    // overflow-conscious code
   int oldCapacity = elementData.length;
   //新容器的大小,是原容器的长度加上原容器一半的长度,即1.5原容器的大小
   int newCapacity = oldCapacity + (oldCapacity >> 1);
   if (newCapacity - minCapacity < 0)
       newCapacity = minCapacity;
   //MAX_ARRAY_SIZE 是容器的最大容量,为Integer的最大值减8.
   if (newCapacity - MAX_ARRAY_SIZE > 0)
       //如果扩容后的容量大于Integer的最大值减8,做一个最大容量缓冲器即int的最大值
       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;
}


//Arrarys.java的方法
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底层是调用C++方法实现 
    System.arraycopy(original, 0, copy, 0,
        Math.min(original.length, newLength));
    return copy;
}

四 在指定位置插入数据

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

//插入位置校验
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

五 set方法

public E set(int index, E element) {
    //index合法性验证
    rangeCheck(index);
    //去除旧的元素
    E oldValue = elementData(index);
    //设置新的元素
    elementData[index] = element;
    //返回旧的元素
    return oldValue;
}

六  get方法

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

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

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
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值