一、底层数据结构
transient Object[] elementData; //定义了一个Object元素类型的数组
private int size;//数组的长度
二、构造函数
private static final int DEFAULT_CAPACITY = 10;//默认的初始容量为10
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//用于空实例的空数组实例。如 ArrayList list = new ArrayList<>() list就等于{}
//初始化ArrayList的容量大小
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);
}
}
//无任何入参,实例化一个空的数组实例
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class) //这个地方之所以要比较,是因为c.toArray()返回的不一定是object[],这是jdk的一个bug,详情可以看see 6260652 【这个编号代表JDK bug库中的编号】
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
+-----------------------------------------------------
其他版本的jdk写法
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
elementData = EMPTY_ELEMENTDATA;
}
}
三、自动扩容
public void ensureCapacity(int minCapacity) {
//判断需要扩容的数组是否为空实例(空数组)如果为不为空,变量等于0, 为空则变量等于数组默认容量 10[意味着不需要扩容,取默认大小即可]
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
if (minCapacity > minExpand) {//如果需要扩容的量大于定义的变量,则进行扩容操作
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)//需要扩容的量大于原数组的长度,则真正进行扩容操作
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//要分配的数组的最大大小
private void grow(int minCapacity) {
int oldCapacity = elementData.length; //原数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1); //原数组的长度+原数组的长度/2
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity; // 系统给予的扩容策略所扩的容量<用户给的扩容量,则改用用户指定扩容量
if (newCapacity - MAX_ARRAY_SIZE > 0)// 如果需要扩容的量大于了本类中定义的最大扩容限制,则扩容到 int 类型最大长度
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);// 扩容,其实调用的的是数组的复制方法
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
// 如若需要扩容的量大于了最大限制,则扩容量改为 int 最大限制量:2147483647。否则为本类中所限制长度:2147483647-8
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
四、其他方法
add(), addAll():该方法是向list中添加一个或者多个元素,默认是往最后添加;同时,也是可以指定位置进行添加的。
+---在这个过程中,会先检查空间是否有剩余,指定位置的时候还会校验位置,而且会存在元素移动的情况,addAll时间复杂度都是线性递增的
set():由于底层是数组,指定位置赋值即可。
get():需要注意的地方是:由于底层是Object元素,取值的时候需要进行类型转换。
remove():删除指定位置的元素,需要将后面的元素向前移动一个位置。而且为了让GC起到作用,最后一个元素必须手动赋值null,也就是手动清除该引用。
trimToSize():将底层数据容量调整为实际存放元素大小容量。
indexOf(), lastIndexOf():获取元素第一个出现的位置,包括null第一次出现的位置,主要是使用for循环,使用equal进行匹配。