ArrayList数据结构
ArrayList底层用数组实现。
数组的特点:
- 查找快:按下标查找,时间复杂度为O(1)
- 删除慢:删除时需要将删除位置后面所有的元素向前移动一个位置,时间复杂度为O(n)
- 插入:
- 非尾部插入慢:需要将插入位置后面的元素全部向后移动一位,时间复杂度为O(n)
- 尾部插入快:直接插入到数组arr[arr.length]位置,时间复杂度为O(1)
实现的接口
-
List:定义了集合的常用操作
-
标记接口:
-
RandomAccess:标记接口,说明该类支持随机访问,大部分是基于数组实现
-
Cloneable:说明该类支持拷贝,ArrayList的clone()方法。
-
浅拷贝:拷贝出来的对象不是独立的对象,相当于只是拷贝了栈中的引用,引用指向的对象还是同一个对象。
-
深拷贝:创建出一个新的对象
-
-
Serializable:序列化,将对象存入磁盘持久化或者网络传输
-
构造方法
-
ArrayList(int initialCapacity):指定数组容量构造方法
/** * 指定数组容量创建数组 */ public ArrayList(int initialCapacity) { //大于0按传入创建,等于0直接指向空数组,负数抛异常 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
-
ArrayList():无参构造方法
/** * 午餐构造方法,常用,指向默认空数组(节省内存空间,new多个对象不添加元素时,只会有一个数组) */ public ArrayList() { //创建的时候数组指向默认的空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
ArrayList(Collection<? extends E> c):根据一个集合构建ArrayList
/** * 根据集合创建list,如果传入的集合为空,直接将数组指向默认数组 */ 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 { // 如果传入的集合元素为0,指向默认空数组 this.elementData = EMPTY_ELEMENTDATA; } }
add方法和扩容
当ArrayList被创建(调用无参构成方法),将数组默认指向默认的数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA)。此时List的数组是一个空数组。调用add方法,调用扩容方法:有两种情况,需要扩容,不需要扩容。如果将要添加的数组元素个数大于数组的长度时,需要扩容(调用默认构造方法,第一次调用add都需要进行扩容)。如果小于则不进行扩容,直接使用尾插法将元素添加到数组末位。
数组扩容逻辑,源码grow()方法。默认扩容之前数组大小的1.5倍,如果是默认创建,则第一次创建一个数组容量为10的数组,如果非第一次扩容,如果扩容1.5被小于元素个数,则按元素个数(+将添加的个数)扩容。根据计算好的新数组容量,调用工具类Arrays.copyOf方法创建新数组,将旧元素赋值到新数组上。
public boolean add(E e) {
//扩容,如果调用默认构造方法,第一次进来elementData数组是个空数组。数组无法改变长度。size默认为0
ensureCapacityInternal(size + 1);
//存放元素,size是元素个数
elementData[size++] = e;
return true;
}
/**
* 调用默认构造方法时,第一次调用add触发扩容minCapacity为1
*/
private void ensureCapacityInternal(int minCapacity) {
//判断数组elementData是否为默认数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA(调用默认构造方法是会指向它)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果指向默认数组,取默认值10和传入的minCapacity大的值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//扩容
ensureExplicitCapacity(minCapacity);
}
/**
*扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
//操作数 + 1
modCount++;
//如果元素个数小于数组长度则不进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容
*/
private void grow(int minCapacity) {
//获取数组之前的长度
int oldCapacity = elementData.length;
//通过之前数组长度算出之后的数组长度。扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果计算出来的数组长度小于传入的长度,则用传入的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//大于int最大值取最大值
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//根据新的大小创建新的数组
elementData = Arrays.copyOf(elementData, newCapacity);
}