一、构造方法
ArrayList有三个构造方法:
ArrayList()
ArrayList(int)
ArrayList(Collection<? extends E>)
1、无参构造方法:
ArrayList中储存数据的其实就是一个数组,这个数组就是elementData,
public ArrayList() {
super();//调用父类中的无参构造方法,父类中的是一个空的构造方法
this.elementData = EMPTY_ELEMENTDATA;//是一个空的Object[],将elementData初始化。空的Object[]会默认大小10
}
2、有参构造:
public ArrayList(int initialCapacity) {
super();//父类中空的构造方法
if(initalCapacity < 0) {//判断如果自定义大小的容量小于0,则报下面这个非法数据异常
throw new IllegalArgumentException("Illegal Capacity" + initialCapacity);
this.elementData = Object[initialCapacity]
//将自定义的容量大小当成初始化elementData的大小。
}
}
总结:ArrayList的构造方法就做一件事情,就是初始化一下存储数据的容器,其实本质就是一个数组,在其中就叫做elementData。
二、核心的方法:
1、增:
- add(E e); 添加集合元素到集合末尾。
- add(int index, E e); 在list集合指定下表位置添加元素。
- addAll(Collection<? extends E> c); 添加一个集合到当前集合的末尾(参数集合是元素类型是当前集合的子类或者当前约束类型)。
- addAll(int index, Collection<? extends E> c); 在指定下标位置,添加参数集合(注意约束集合的类型)
- boolean add(E);添加一个特定的元素到list的末尾。
public boolean add(E e) {
确定内部容量是否够了,size是数组中数据的个数,因为要添加一个元素,所以size+1;
需要先判断size+1 的这个个数数组能否放得下,就在这个方法中判断是否数组。length够用。
ensureCapacityInternal(size + 1);
在数据的正确位置上放置元素e, 并且size++
elementData[size++] = e;
return true;
}
- ensureCapacityInternal(xxx);确定内部容量的方法:
private void ensureCapacityInternal(int minCapacity){
判断初始化的elementData是不是空数组
if (elementData == EMPTY_ELEMENTDATA) {
如果为空的话,minCapacity=size+1;空的数组没有长度就存放不下了,所以就将minCapacity变成默认大小10;
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
- ensureExplicitCapacity(xxx);
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0) {
grow(minCapacity);数组自动扩容
}
}
1、minCapacity如果大于了实际elementData的长度,就说明elementData数组的长度不够用,就要增加elementData的length。
2、由于elementData初始化时是空的数组,那么第一次add的时候minCapacity=size+1;也就minCapacity=1,在上一个方法(确定内部容量ensureCapacityInternal)就会判断出是空的数组,就会给将minCapacity=10,到这一步为止,还没有改变elementData的大小。
3、elementData不是空的数组了,那么在add的时候,minCapacity=size+1;也就是minCapacity代表着elementData中增加之后的实际数据个数,拿着它判断elementData的length是否够用,如果length不够用,那么肯定要扩大容量,不然增加的这个元素就会溢出。
- ArrayList核心grow(xxx)数组扩容方法:
private void grow(int minCapacity) {
//1、将扩充前的elementData大小给oldCapacity
int oldCapacity = elementData.length;
//2、数组扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//3、初始化elementData的大小
if (newCapacity < minCapacity )
newCapacity = minCapacity;
//4、如果newCapacity超过了最大的容量限制,将能给的最大值给newCapacity
if (newCapacity > MAX_ARRAY_SIZE)
newCapacity = hugeCapacity(minCapacity);
//5、新的容量大小已经确定,拷贝数组,改变数组容量
elementData = Arrays.copyof(elementData, newCapacity);
}
- hugeCapacity(); 赋值最大值
private static int hugeCapacity(int minCapacity) {
if(minCapacity < 0)
throw new OutOfMemoryError();
//如果minCapacity都大于MAX_ARRAY_SIZE,那么就Integer.MAX_VALUE返回,反之将MAX_ARRAY_SIZE返回。因为maxCapacity是三倍的minCapacity,可能扩充的太大了,就用minCapacity来判断了。
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
- void add(int index, E e); 在特定位置添加元素。
public void add(int index, E element) {
//检查index也就是插入的位置是否合理。
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1);
//这个方法就是用来在插入元素之后,要将index之后的元素都往后移一位,
System.arraycopy(elementData, index, elementData,index + 1, size - index);
//在目标位置上存放元素
elementData[index] = element;
size++;//size增加1
}
- rangeCheckForAdd(index)
private void rangeCheckForAdd(int index) {
if (index > size || index < 0) //插入的位置不能大于size和小于0
//报错越界异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}