存储特性 – 有序且可重复
- 存储元素,底层 Object 数据,数组不会对元素做判断,所以可重复,基于数组下标的连续存储,所以有序
- 数组容量一旦定义,就不能更改,可以扩容
初始容量 – 默认情况下,arrayList初始大小为 0
存储满后 – 扩容大小是原来的1.5倍
源码add方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 版本号
private static final long serialVersionUID = 8683452581122892189L;
//设置arrayList默认容量 JDK1.6版本之前 10 1.6版本之后初始化大小为0
private static final int DEFAULT_CAPACITY = 10;
//空数组,当调用无参数构造函数的时候默认给个空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//这才是真正保存数据的数组
private transient Object[] elementData;
//arrayList的实际元素数量
private int size;
//构造方法传入默认的capacity 设置默认数组大小
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);
}
}
// 无参数构造方法默认为空数组
// 当前arrayList初始化构建的时候,底层的object数组长度为0
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//构造方法传入一个Collection, 则将Collection里面的值copy到arrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
//下面主要看看ArrayList 是如何将数组进行动态扩充实现add 和 remove
public boolean add(E e) {
// size + 1 计算当前存储元素所需的数组最小长度
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 第一次调用 calculateCapacity(elementData, minCapacity) = 10
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// elementData 空数组,长度0
// 超出了数组可容纳的长度,需要进行动态扩展
if (minCapacity - elementData.length > 0)
// arrayList扩容实现 minCapacity = 10
grow(minCapacity);
}
// 传递 minCapacity = 10
private void grow(int minCapacity) {
// overflow-conscious code
// 获取数组原本长度
int oldCapacity = elementData.length;
// oldCapacity 右移一位,第一次执行,数组长度0,所以还是0
// 不是第一次执行,oldCapacity >> 1 == 10(1010) >> 1 == 5(101)
// 设置新数组的容量扩展为原来数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
// 不够就将数组长度设置为需要的长度
// 只有第一次执行的时候才会进入
if (newCapacity - minCapacity < 0)
// 如果第一次执行,newCapacity = 0 minCapacity = 10
// 初始容量在此定义为 10
newCapacity = minCapacity;
//判断有没超过最大限制
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 将原来数组的值copy新数组中去, ArrayList的引用指向新数组
// 这儿会新创建数组,如果数据量很大,重复的创建的数组,那么还是会影响效率,
// 因此鼓励在合适的时候通过构造方法指定默认的capaticy大小
elementData = Arrays.copyOf(elementData, newCapacity);
}
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 判断 elementData 是否为空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 只有第一次调用add方法才会进入
// DEFAULT_CAPACITY = 10
// minCapacity = 1
// 调用max方法,返回 10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// a = 10 , b = 1
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
}
源码remove方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
// 后面的每个值挨个前移一个位置
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData,index+1,elementData,index,numMoved);
// 最后一个值置为空
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
总结
- arrayList 在JDK1.6之前默认长度10,1.6之后默认为 0
- 当用户第一次调用add方法时,arrayList会进行第一次扩容,扩容后大小为 10
- arrayList在添加第11个元素的时候,会进行第二次扩容
- 迭代数组的时候,如果删除数组元素,后面数组元素就会前移一个位置,所以就会引起并发修改异常,解决:
- 不使用迭代器,for循环即可
- CopyOnWriteArrayList 可读写的ArrayList