Java集合 - List之ArrayList扩容详解

ArrayList简介

ArrayList是Java中常用的Collection集合实现类,底层由Object数组实现。与array数组相比,它具有动态扩展的能力(动态扩容)。

ArrayList继承关系

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

ArrayList类继承AbstractList(抽象类),实现了List接口,Cloneable接口(克隆),RandomAccess接口(随机访问),Serializable接口(序列化)。

List接口继承了Collection接口,Collection接口继承了Iterable接口,故ArrayList是Collection接口的实现子类,同样也是Iterable接口(迭代器)的实现子类,同时具有迭代器的方法。

        ArrayList list = new ArrayList(3);
        list.add(1);
        list.add(2);
        list.add(3);
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

ArrayList源码分析

重要的成员变量如下:

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

//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};

//与空数组elementData区分开,调用ArrayList无参构造器时候,赋值给elementData 
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//真正存放element的数组
transient Object[] elementData; // non-private to simplify nested class access

//数组的真实长度
private int size;

1.无参构造

/**
* 当调用ArrayList无参构造器时,底层elementData数组被初始化为一个空数组
*/
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

2.有参构造

/**
 * 当入参initialCapacity大于0时,底层elementData数组会被初始化为指定大小的Object数组
 * 当入参initialCapacity等于0时,底层elementData数组会被赋值为一个空数组(EMPTY_ELEMENTDATA)
 * 当入参initialCapacity小于0时,直接抛IllegalArgumentException异常
 */
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);
	}
}

3.add(E e)方法

public boolean add(E e) {
	ensureCapacityInternal(size + 1);  
	
	//以上代码执行完成后,将对象添加到数组中
	//size增加1
	elementData[size++] = e;
	//返回添加成功
	return true;
}
// 首先ArrayList执行add方法时,
// 先获取底层存储对象的数组真实长度size
// 添加对象时,意味着minCapacity(最小容量)应该等于原来的size + 1
private void ensureCapacityInternal(int minCapacity) {
	
	//如果底层数组elementData为空数组
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
	
	//那么minCapactity就等于(DEFAULT_CAPACITY(也就是10)与minCapacity 之间取最大的那个值)
		minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	}

	ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
	
	//数组更改次数(每次增加一个对象,更改次数就加1)
	modCount++;

	// 当调用的是无参构造器声明ArrayList并且第一次添加对象时,minCapacity=10,elementData.length=0
	// 当ArrayList底层数组已经被填满时,再添加对象时,minCapacity(最小所需容量)就会大于底层数组的长度,进而触发扩容
	if (minCapacity - elementData.length > 0)
		
		// 上面条件成立,执行grow方法
		grow(minCapacity);
}

//真正的扩容方法
private void grow(int minCapacity) {
	
	// 获取底层数组elementData的长度
	int oldCapacity = elementData.length;
	
	// newCapacity = oldCapacity + oldCapacity / 2
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	
	// newCapacity 小于 minCapacity,将minCapacity的值赋给newCapacity
	if (newCapacity - minCapacity < 0)
		newCapacity = minCapacity;
	if (newCapacity - MAX_ARRAY_SIZE > 0)
		newCapacity = hugeCapacity(minCapacity);
	
	// 执行扩容,并将原数组数据拷贝进来
	elementData = Arrays.copyOf(elementData, newCapacity);
}

add方法总结:

1.调用无参构造器创建ArrayList

        ①首次add对象时,ArrayList底层数组的容量会先被初始化为10。

        ②当ArrayList底层数组被填满后,再次add对象时,底层数组的容量会扩容至原来的1.5倍,并将原数组数据拷贝进来。

3.调用有参构造器创建ArrayList

        ①首先将底层数组初始化为指定入参的大小。

        ②当ArrayList底层数组被填满后,再次add对象时,底层数组的容量会扩容至原来的1.5倍,并将原数组数据拷贝进来。

ArrayList的特点

1.由于ArrayList底层是Object数组,因此查询速度较快

2.add(E e)方法默认是从底层数组的末尾进行添加,所以时间复杂度为O(1)

3.add(int index, E element)方法,指定位置添加对象,其时间复杂度为O(n),因为数组要在index增加成员,势必会造成数组索引的变化(涉及到移动其他成员)。

4.remove(int index)方法,也会导致数组索引的变化。所以ArrayList 增删相对较慢

5.ArrayList中的方法是非线程安全的,因此多线程环境下操作集合,不推荐使用ArrayList。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值