简介
ArrayList的底层是数组,继承自AbstractList,同时还实现了RandomAccess、Cloneable、Serializable接口,所以ArrayList 是支持快速访问、复制、序列化的。
基础常量
/**
//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
//
private static final Object[] EMPTY_ELEMENTDATA = {};
//
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//保存数据的数组
transient Object[] elementData; // non-private to simplify nested class access
//数组大小
private int size;
//最大长度=Integer的最大长度-8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
常用方法
构造器:
//无参构造 这个时候的数组大小为0
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//初始化大小 传的值大于0的话 集合大小就是initialCapacity的大小 等于0 集合大小为0 小于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的集合
public ArrayList(Collection<? extends E> c) {
//先对传进来的集合进行复制
elementData = c.toArray();
//判断这个集合是否为空
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//判断这个集合是否为object类型
if (elementData.getClass() != Object[].class)
//不是object类型的话对c集合进行转换重新复制
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
//c集合为空list集合为{}
this.elementData = EMPTY_ELEMENTDATA;
}
}
get方法:
public E get(int index) {
rangeCheck(index); //判断这个下标是否超出数组大小
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
首先调用get方法,然后进入 rangeCheck()方法,将下标传入方法判断这个下标是否超出数组大小,然后进入elementData()方法,将数组为index的数据直接返回。
add方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 看数组是否需要扩容
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {.
//判断数组是否为首次添加数据 设置数组大小
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 判断你传进来的下标是否超过数组的长度
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容0.5倍
//这是扩容之后的长度小于size+1; (size+1)+size*0.5超出integer的最大长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//扩容之后的长度大于MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
主要就是扩容,有多种情况,首先第一种:没有超过最大的长度也不是负数,正常扩容。
第二种:传进来一个数,扩容之后大于最大数组长度,进入第二个判断,判断我们的size+1是否大于数组最大长度,如果大于返回integer的最大长度,否则返回最大数组长度,然后进行扩容。
第三种:传入一个数,扩容之后小于size+1,进入第一个判断让扩容之后的大小=size+1,然后再判断这个size+1是否大于数组最大长度,大于的话扩容到integer的最大值,否则扩容到数组最大长度。
然后为什么是扩容0.5倍+1呢 是因为我们的传进来的size已经+1 然后再通过位运算 就得到了数组长度=(length+1)+length*0.5;
remove方法:
public E remove(int index) {
rangeCheck(index); //判断下标是否超出
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1; //这个index后面有多少位数据 也就是要拷贝多少位
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);//数组拷贝的方法
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
Object src : 原数组
int srcPos : 从元数据的起始位置开始
Object dest : 目标数组
int destPos : 目标数组的开始起始位置
int length : 要copy的数组的长度
下面是一个示例图:
相对于查询来说,添加和删除的效率是较低的 因为删除要去循环数组,添加的话如果需要扩容也是需要重新生成一个新的数组,然后再去copy数组。
这都是它的一些基础的一个方法解析,如果理解错误,还请各位大牛帮忙指正!!!!