This class is a member of the Java Collections Framework.
arraylist是Collections中的一员,底层的存储数据结构是一个Object数组,这就意味着arraylist存放的数据类型只能为引用数据类型、NULL,引用数据类型包括(Integer、String、Boolean、Char、Byte、Float、Double、Long、Short)。而且。数组的优点有查询快、时间复杂度为o(1)。缺点:长度固定无法自动扩容,但是arraylist会自动扩容
transient Object[] elementData;
空参构造函数
给elementData声明了一个默认的空的数组实例,从这里可以看出我们在new一个arraylist的时候,arraylist这时候还是一个空的数组。为了减少内存开销嘛,也合情合理。
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
带参构造函数
这个其实就是指定arraylist容量大小的,为elementData赋值。其中arraylist中的elementData与size我们需要做一个区分。
- elementData.length:arraylist容量的大小
- size:arraylist添加元素的个数、arraylist.size也是指的这个size、也是arraylist是否为empty的标志
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
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);
}
}
接着看另外的带参数的构造函数,这个参数的类型是一个Collection的类型,可以传List(arraylist、linklist、list的儿子…)。类似linklist向arraylist的转换、或者说是arraylist间的拷贝
public ArrayList(Collection<? extends E> c) {
//把参数数组化
Object[] a = c.toArray();
//入参的长度不为0
if ((size = a.length) != 0) {
//入参是arraylist类型的直接赋值
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
//其他类型的转成数组在进行赋值
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
//入参长度为0,直接赋值空数组
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
接下来看contains方法,根据元素下标来判断的。如果arraylist包含元素一定有下标且为正数。其余情况为不包含返回负数
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
//说明arraylist可以添加null
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
//elementData中有此值,返回值的下标
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
接下来看add方法,这个方法算是arraylist的核心方法了,逐层剖析下面几个方法。
- ensureCapacityInternal 确保内部容量
- ensureExplicitCapacity 是否需要扩容
- calculateCapacity:计算容量
javascript boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
calculateCapacity方法:计算容量 这里只是单纯的计算容量分为俩种情况
- arraylist 第一次添加元素
- arraylist 非第一次添加元素
new ArrayList() 第一次添加元素size == 0、elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {},此时初始化arraylist,初始化容量为10
new ArrayList(4) 第一次添加元素size == 0、elementData==EMPTY_ELEMENTDATA = {},此时初始化arraylist,初始化容量为1
DEFAULTCAPACITY_EMPTY_ELEMENTDATA != EMPTY_ELEMENTDATA
其他非第一次添加元素直接size++
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果此时elementData并没有初始化,所以elementData=={}、size==0,此时初始化arraylist容量为DEFAULT_CAPACITY == 10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//其他情况下直接返回size+1
return minCapacity;
}
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
ensureExplicitCapacity方法: 判断是否需要扩容、是否扩容了都记录修改次数
扩容的条件:计算出来的minCapacity最小容量>此时arraylist的容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
其中modCount是一个标识符号,记录修改次数的
protected transient int modCount = 0;
grow方法:初始化容量 无参的arraylis进行add()时候调用grow()是初始化容量
grow方法:扩容 当计算出来的容量>arraylist当前的容量,进行扩容增长elementData数组的长度
扩容规则:
- 计算出来的容量<1.5倍旧容量 新容量=1.5倍扩容
- 计算出来的容量>1.5倍旧容量 新容量=计算出来的容量
- 1.5倍旧容量> MAX_ARRAY_SIZE 新容量=interger.max
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//1.5倍的情况下还是不满足,直接扩大容量至计算出来的那个容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//新容量比计算机能承受的最大容量-8还大,最大容量为integer.length
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//扩容数组且copy给elementData
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
ensureCapacityInternal方法: 容量保证充足可以添加进去元素,开始真正添加元素
到此arraylist添加元素就和普通数组添加元素一样了
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
附页(反射查看arraylist容量大小)
- 无参arraylist第一次执行add方法的时候容量为10,未执行add方法容量为0
- 带参arraylist在创建arraylis对象的时候即指定了容量
ArrayList<Object> list = new ArrayList<>();
list.add(1);
Class clazz=Class.forName("java.util.ArrayList");
Field elementData=clazz.getDeclaredField("elementData");
elementData.setAccessible(true);
Object[] arr=(Object[]) elementData.get(list);
//容量大小
System.out.println(arr.length);