Java集合——ArrayList源码

一、ArrayList数据结构
ArrayList底层是数组实现的,数组元素的类型是Object类型,可以动态的增长和缩减。
ArrayList先继承AbstractList,AbstractList实现List接口
二、ArrayList的属性

    //版本号
    private static final long serialVersionUID = 8683452581122892189L;
    //初始化默认值
    private static final int DEFAULT_CAPACITY = 10;
    //指定ArrayList容量为10时,返回该空对象数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
     //调用无参构造方法时,返回该空对象数组。它与EMPTY_ELEMENTDATA最大的区别是:该数组是默认返回的,而EMPTY_ELEMENTDATA是用户指定容量为0时返回的
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //存储元素数组
    transient Object[] elementData;
    //元素大小
    private int size;
    //最大数组容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

三、构造方法
ArrayList有三个构造方法
(1)ArrayListint (int initialCapacity)

/*指定一个初始容量为initialCapacity的空ArrayList*/
 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);
        }
    }

(2)ArrayList()

/* 构造一个初始容量为 10 的空列表 */
  public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  }

(3)ArrayList(Collection<? extends E> c)

/*构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的*/
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;
        }
    }

四、核心方法
(1)add(E e):将元素添加到列表的尾部

 public boolean add(E e) {
        //判断容量是否够用
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //在正确的位置上存入元素e,并且size++
        elementData[size++] = e;
        return true;
 }

//数组容量检查,不够时进行扩容,minCapacity为需要的最小容量
 public void ensureCapacity(int minCapacity) {
        //如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA则最小扩容为10,否则为0
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        //如果需要的最小容量大于最小扩容容量,则使用需要的最小容量
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

//数组容量检查,不够时进行扩容
 private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            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 void grow(int minCapacity) {
        //获取当前数组的容量
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //进行扩容,新的容量=旧的容量+旧容量/2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果扩容后的容量小于需要的最小容量
        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);
  }

//进行大容量分配
private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
        //如果需要的容量大于MAX_ARRAY_SIZE,分配 Integer.MAX_VALUE 否则分配MAX_ARRAY_SIZE
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

总结:
add(E e)方法进行扩容的步骤:
①先进行空间检查,看是否需要扩容,若需要扩容,确定最少需要扩容的容量
②确定扩容后,执行grow(int minCapacity)方法,minCapacity为最小需要扩容的容量
③第一次扩容, newCapacity = oldCapacity + (oldCapacity >> 1);在原有容量基础上增加一半
④第一次扩容后,判断容量是否还小于需要的最小扩容容量minCapacity,若还小于,将容量扩充为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);  // Increments modCount!!
        //对数组进行复制,空出index的位置插入加入的元素
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //将index位置赋值为性加入的元素
        elementData[index] = element;
        //容量+1
        size++;
 }

//越界检查
private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

总结:
①越界检查,若越界抛出异常
②确定容量,判断容量是否足够,不够进行扩容
③移动元素,腾出需要插入元素的空间,插入元素

(3)remove(int index):删除指定位置的元素

public E remove(int index) {
        rangeCheck(index);//越界检查

        //结构性修改次数+1
        modCount++;
        E oldValue = elementData(index);//将要删除的元素值存放在oldValue

        int numMoved = size - index - 1;//计算删除元素后需要移动的元素个数
        if (numMoved > 0)//如果需要移动的元素个数大于0,则需要把要删除元素之后的所有元素向左移动
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //将要删除的元素置null,size-1                 
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

总结:
删除指定位置的元素:
①越界检查,若越界抛出异常
②计算需要移动的元素个数,元素个数大于0,则需要把要删除元素之后的所有元素向左移动,覆盖掉要删除的元素
③删除的元素赋值为null

4)remove(Object 0):移除此列表中首次出现的指定元素

    public boolean remove(Object o) {
      //找到需要删除元素的index值,用fastRemove(index)方法进行删除
        if (o == null) {//此处证明ArrayList可以有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) {
         //结构性修改次数+1
        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
    }

(5)set(int index,E element):用指定的元素替代此列表中指定位置上的元素

    public E set(int index, E element) {
        //检查是否越界
        rangeCheck(index);

        E oldValue = elementData(index);//将被替换的元素存放在oldValue中
        elementData[index] = element;//用新元素替换旧元素
        return oldValue;
    }

(6)get(int index):返回此列表中指定位置上的元素

    public E get(int index) {
        //检查是否越界
        rangeCheck(index);
       //返回索引为index的元素
        return elementData(index);
    }
     //返回索引为index的元素
     E elementData(int index) {
        return (E) elementData[index];
    }

总结:
ArrayList底层本质是elementData数组,在数据的查询方面会很快,但是在增加、删除方面相对慢点,因为有可能需要移动大量的元素。ArrayList初始容量为10,根据需求会进行相应的扩容。

ArrayList和Vector的区别:
①ArrayList是线程不安全的,Vector是线程安全的(synchronized),当多条线程访问同一个ArrayList集合时,需要手动保证该集合的同步性,而Vector则不用。
②ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%(newCapacity = oldCapacity + (oldCapacity >> 1)),Vector默认增加为原来的一倍(newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值