首页 > 代码库 > Java知识树 集合 ArrayList

Java知识树 集合 ArrayList

简要说明

ArrayList,实现了List接口,它是一个有序集合,即元素排列的顺序和添加元素的顺序一致,我们可以通过下面的示例代码和结构图来理解刚刚这句话。

示例代码:

List<Integer> list = new ArrayList<Integer>(); 
list.add(
6);
list.add(
4);
list.add(
7);
list.add(
6);
list.add(
1);

结构图:

技术分享

 

通过上面的结构图我们可以知道ArrayList的底层是由数组来实现的,但它与数组的区别在于ArrayList的容量会动态增长,这意味着因存储元素导致容量不足时ArrayList会自动扩大数组的容量。这一过程的细节会在源码分析阶段进行说明。

 

我们在创建ArrayList时若不指定初始容量大小,则初始容量大小会默认为10,即一个能存储10个元素的数组。(注①)当然我们也可以根据实际的存储需要手动指定初始容量大小,见如下示例代码:

List<Integer> list = new ArrayList<Integer>(5);

请记住,即便指定了初始容量大小,当因存储元素导致容量不足时,ArrayList依然会自动扩容。那么这个扩容是否会有一个上限呢?答案是肯定的,具体细节会在源码分析阶段说明。

 

注①:在jdk1.6版本中这句话是没有问题的,但在jdk1.7版本中ArrayList()这一构造器的内部实现做了改进。可见如下源码对比:

//jdk1.6的实现
public ArrayList() {
    this(10);
}

//this(10)是调用了另外一个构造器ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = http://www.mamicode.com/new Object[initialCapacity];
}

//this.elementData就是一个用来存储元素的数组
private transient Object[] elementData;



//jdk1.7的实现
public ArrayList() {
     super();
     this.elementData =http://www.mamicode.com/ EMPTY_ELEMENTDATA;
}

//EMPTY_ELEMENTDATA是一个已经初始化了的数组,不过它的容量为0
private static final Object[] EMPTY_ELEMENTDATA = http://www.mamicode.com/{};

我们可以对jdk1.7的改进稍作分析:当调用ArrayList()时,仅初始化了数组但并未指定容量,故此时数组的长度为0,这样做也许是为了避免存储空间的浪费。若按照之前jdk1.6的做法,只要通过ArrayList()这一构造器来创建ArrayList,那么就会初始化一个容量为10的数组,如果这个ArrayList不被使用,那么这10个容量的数组就浪费了,这样的ArrayList越多,浪费的数组也就越多。采用jdk1.7的做法虽然一样初始化了数组,但并未指定容量,这样即便创建出的ArrayList不被使用,也不至于造成存储空间的浪费。对于jdk1.7的改进我们可以提出一个疑问?通过ArrayList()这一构造器来创建ArrayList,它是在什么时候指定数组容量的呢?答案是在调用add(E e)或add(int index, E element)方法时,具体的细节会在源码分析阶段进行说明。

 

ArrayList实现了RandomAccess接口,提供了随机访问功能,即可以通过索引快速访问该索引所对应的元素。那么这个随机访问又是一个怎样的过程?这个问题也会在接下来的源码分析阶段得到解答。

 

最后需要注意的是ArrayList是非线程安全的,这意味着在多线程环境下使用它是有很大风险的。因此在多线程环境下建议使用Vector来替代它。

 

 

 

源码分析(基于jdk1.6.0_45

在创建一个ArrayList时,我们需要调用它的构造器,在不指定初始容量的情况下我们可以调用ArrayList(),如果明确了要存储的元素容量,可以调用ArrayList(int initialCapacity)来创建一个带有指定容量的ArrayList

 

//这虽然也是ArrayList的一个构造器,但从内部实现来看,它是调用了ArrayList(int initialCapacity)这一构造器。当我们不指定数组初始容量大小时,默认传入的initialCapacity的值是10,即一个容量为10的数组。
public ArrayList() {
    this(10);
}

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = http://www.mamicode.com/new Object[initialCapacity];
}

//用于存储元素的数组,当ArrayList的构造器被调用时进行初始化
private transient Object[] elementData;

 

 

 

 

--------------------未完,待更新--------------------

Java知识树 集合 ArrayList