集合之JDK1.8的ArrayList源码

在list集合中,ArrayList是最为常见的。通过了解底层代码来进一步了解ArrayList。
一、ArrayList的继承关系与属性

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

继承关系:可以看到ArrayList继承的是抽象类AbstractList类,同时实现了list(规定了List的操作规范)等接口。
RandomAccess:表示可以随机访问
Cloneable:可以clone
Serializable:实现了序列化接口,可以将实现了Serializable接口的对象转换
为字节序列
属性:

// 缺省容量
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素数组,使用关键字transient 避免被序列化
transient Object[] elementData;
// 实际元素大小,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

二、构造方法

//无参构造函数,给定一个默认的空数组
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
//通过判断传入值的大小,来初步确定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);
        }
    }
传入的是集合类型:先转化为数组类型,然后判断数组类大小,同时给elementData赋值
  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) //是否转化为Object数组
                elementData = Arrays.copyOf(elementData, size, Object[].class); //没有转化就复制
        } else {  //如果是空集合,则直接赋值空数组
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

三、常用API
1.add(E e)

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

执行add()第一步是执行ensureCapacityInternal(size + 1);可以看做是确定集合长度,即保证elementData有足够大大小。

 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

 private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断数组是否为空
            return Math.max(DEFAULT_CAPACITY, minCapacity);//为空,则返回最大值
        }
        return minCapacity;//否则,返回最小值
    }
    
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        //当返回d的最小值大于数组的长度时候,执行下列方法,对数组进行扩容
            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); // 指定新容量
        // 拷贝扩容
        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;
    }

2.add(int index, E element) 指定位置添加数据

public void add(int index, E element) {
        rangeCheckForAdd(index); //检查指定位置是否合理

        ensureCapacityInternal(size + 1);  // 同理于add()方法
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index); //采用System复制进行数据插入,同时看数据是否需要移位
        elementData[index] = element;
        size++;
    }
    
 private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
   // System.arraycopy 解析
  public static native void arraycopy(Object src,  int  srcPos,
                                      Object dest, int destPos,
                                      int length);
    Object src : 原数组
    int srcPos : 从元数据的起始位置开始
  Object dest : 目标数组
  int destPos : 目标数组的开始起始位置
  int length  : 要copy的数组的长度

3.remove(int index)

public E remove(int index) {
        rangeCheck(index); //检查下标的合理性

        modCount++;
        E oldValue = elementData(index);  //得到下标对应的值

        int numMoved = size - index - 1;  //数组长度-1,判断数据是否需要左移
        if (numMoved > 0)  //执行arraycopy
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
        //数组最后一个置null,方便系统GC回收
        return oldValue;
    }

4.clear() 数组置为空,同时系统是调动GC进行回收

 public void clear() {
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

5.indexOf(Object o)

 public int indexOf(Object o) {
        if (o == null) {  //说明了数组中可以存在null值
            for (int i = 0; i < size; i++)
                if (elementData[i]==null) //找到第一个就直接返回
                    return i;
        } else {       //如果不是null值
            for (int i = 0; i < size; i++) // 遍历数组,找到第一个和指定元素相等的元素,返回下标
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1; //没有的话,则返回-1
    }

6.set(int index,E e)

public E set(int index, E element) {
        rangeCheck(index);  //检查合法性

        E oldValue = elementData(index); 
        elementData[index] = element; //用传入的值覆盖原来d的值
        return oldValue;   //返回旧值
    }

四、总结:
ArrayList底层是利用数组实现,可以存在null
ArrayList在查询时候比较方便,但是插入的话,从add(int index, E element)可以看出需要移动大量元素,效率不怎么高
ArrayList在使用for循环和foreach进行数据迭代时候,效率是差不多

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值