JDK1.8,代码:java.util.ArrayList.java
ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList实现了List、RandomAccess接口。可以插入空数据,也支持随机访问。
/**
* 序列化的版本号
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认初始容量10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用于空实例的共享空数组实例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小的空实例的共享空数组实例
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList元素的数组缓冲区
*/
transient Object[] elementData;
/**
* ArrayList的大小
*/
private int size;
构造函数
/**
* 用初始容量作为参数的构造方法
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//初始容量大于0,实例化数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//初始容量等于0,赋予空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 无参的构造方法
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 构造一个包含指定元素的列表集合
* 按照集合返回它们的顺序迭代器
*
* 要将其元素放入此列表的集合;如果指定的集合为空,抛出NullPointerException
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // c为空会抛出NullPointerException
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 用空数组替换
this.elementData = EMPTY_ELEMENTDATA;
}
}
构造方法指定元素列表集合示例:
package com.container.arraylist;
import java.util.ArrayList;
/**
* @Classname ArrayListDemo
* @Description 构造方法指定元素列表集合示例
* @Date 2019/10/19 13:01
* @Created by xiangty
*/
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<A> arrayList = new ArrayList<A>();
A a = null;
for (int i = 0; i < 10; i++) {
a = new A();
a.setA("addValue" + i);
arrayList.add(a);
}
ArrayList arrayList2 = new ArrayList(arrayList);
// 打印arrayList2集合的值
print(arrayList2);
}
public static void demo1() {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
arrayList.add(i);
}
ArrayList arrayList2 = new ArrayList(arrayList);
// 打印arrayList2集合的值
print(arrayList2);
}
public static <E> void print(ArrayList<E> arrayList){
arrayList.forEach((a) -> System.out.println(a));
}
}
class A {
private String A;
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
@Override
public String toString() {
return "A{" +
"A='" + A + '\'' +
'}';
}
}
从上述的构造方法中可知,默认情况下elementData是一个大小为0的空数组,当指定大小的时候,elementData的初始化大小變成了指定的初始化。
ArrayList扩容
ArrayList相当于动态数据,其中最重要的两个属性:elementData
数组和 size
大小。
add(E e)新增方法
/**
* 将指定的元素追加到此列表的末尾
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
首先进行扩容校验
将插入的值放到尾部,并将 size + 1
add(int index, E element)指定位置添加
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//复制,向后移动
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
也是首先扩容校验
接着对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置
ensureCapacityInternal方法
/**
* 确保内部容量
*/
private void ensureCapacityInternal(int minCapacity) {
//先判断数组是否为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果数组为空,将DEFAULT_CAPACITY(为10)和minCapacity中较大的一个赋值给minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
a).当空列表add()第1个元素时,调试可知:原本minCapacity为1,在Math.max()方法比较后,minCapacity为10。
b).但当add()第2个元素时,数组非空,直接进入ensureExplicitCapacity(minCapacity)(此时minCapacity为2)。
ensureExplicitCapacity方法
private void ensureExplicitCapacity(int minCapacity) {
//定义于ArrayList的父类AbstractList,用于存储结构修改次数
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//如果数组的长度(elementData.length)小于最小容量(minCapacity),就扩容
grow(minCapacity);
}
a).当要add第1个元素时,这时elementData.length(为0,因为此时还是空列表)是要比minCapacity(为10)小的,会进入grow(minCapacity)方法(minCapacity为10)
b).当add第2个元素时,调试可知:minCapacity为2,此时elementData.length(即是容量)在添加第一个元素后扩容成10了,比minCapacity大,不会去执行grow方法 。数组容量仍为10。
c).所以当添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。
d).直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容
grow方法进行扩容
/**
* 用来分配数组的size最大值
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
/*
右移一位相当于原数除以2,位运算的计算方式相对除以计算更快
新容量扩大为原来容量的1.5
*/
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//从minCapacity和这个newCapacity中取较大值作为扩容后的新数组长度(新容量)。
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果新容量大于数组的最大size,进入hugeCapacity方法
newCapacity = hugeCapacity(minCapacity);
//将原来数组的数据复制到新的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
当add第1个元素时,oldCapacity为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity 不比 MAX_ARRAY_SIZE大,则不会进入hugeCapacity方法。数组容量为10,add方法中return true,size增为1
第3、4···到第10个元素逻辑同第1个
当add第11个元素时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中return true,size增为11法最后一步,在确定好新数组的大小后,会调用Arrays.copyOf()方法,以适当长度(newCapacity)新建一个原数组的拷贝,并修改原数组,指向这个新建数组
grow()方法最后一步,在确定好新数组的大小后,会调用Arrays.copyOf()方法,以适当长度(newCapacity)新建一个原数组的拷贝,并修改原数组,指向这个新建数组。java垃圾回收机制会自动回收原数组
elementData = Arrays.copyOf(elementData, newCapacity);
hugeCapacity方法
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//对minCapacity和MAX_ARRAY_SIZE进行比较
//若minCapacity大,将Integer.MAX_VALUE作为新数组的大小
//若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
ensureCapacity方法
add方法添加大量数据的时候,为减少分配次数和提高效率,推荐使用ensureCapacity方法
public void ensureCapacity(int minCapacity) {
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);
}
}