java学习笔记之集合—ArrayList源码解析

1、ArrayList简介

ArrayList是一个数组队列,与java中的数组的容量固定不同,它可以动态的实现容量的增涨。所以ArrayList也叫动态数组。当我们知道有多少个数据元素的时候,我们用传统数组就可以解决问题,可当我们不知道有多少个数据元素的时候我们就可以用ArrayList。

2、继承关系

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

它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。

ArrayList 继承了AbstractList实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess接口,即提供了随机访问功能RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。

ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

3、实现原理

transient Object[] elementData;

ArrayList的底层就是一个对象数组,ArrayList类就是对该数组的封装。除了对象数组elementData之外,ArrayList中还定义了空数组(EMPTY_ELEMENTDATA),和默认空数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 。

private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

这两个数组的作用体现在接下来要介绍的ArrayList的构造方法之中。

4、构造方法

无参构造方法

/**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**

无参构造方法中,将 DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组赋给elementData,这样一来,elementData就是一个空数组。

有参构造方法

import java.util.ArrayList;
/**
 * 
 * @author asus
 * 使用给默认长度的方法创建ArrayList对象
 */
public class ArrayListDemo {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ArrayList<String> al = new ArrayList<String>(3);
        al.add("666");
    }
}

我们看一下这种构造方法的源码

//capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时则会采用2倍的形式进行容
           量的扩充
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);
        }
    }

构造了一个指定大小但内容为空的数组,initialCapacity参数就是初始容量大小。

5、ArrayList如何实现容量动态增长

以ArrayList中的add()方法为例,当ArrayList中增加一个数据元素时,意味着ArrayList的容量至少要加1(elementData.length+1),calculateCapacity()将elementData.length+1与默认初始容量DEFAULT_CAPACITY = 10 进行对比,并返回其中更大的数作为最小容量长度 (minCapacity)。再调用方法grow(),将minCapability与ArrayList的容量的2倍(elementData.length + (elementData.length >> 1))进行比较并选择其中更大的数作为ArrayList新的容量newCapability,然后在通过elementData = Arrays.copyOf(elementData, newCapacity);将新的数组赋给elementData。这样一来,ArrayList就成功的完成了数组长度的动态增长。

我们看一下这一过程的源码:

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

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)
            grow(minCapacity);
    }

//将至少需要的容量与原容量的2倍进行比较,确定新的容量
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }

 

posted @ 2020-02-23 21:53  幼儿猿班长  阅读(132)  评论(0编辑  收藏  举报