public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable复制代码
implemnts RandomAccess表明了其拥有随机快速访问的能力,能够根据下标快速访问元素java
ArrayList底层是数组,会占据连续的内存空间(数组的长度>真正数据的长度), 数组的缺点:空间效率不高。
当添加元素,超出现有数组容量时,便会进行扩容操做:
ArrayList的增加因子1,扩容1/2复制代码
public void ensureCapacity(int minCapacity) {//设定初始容量的构造函数
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
?0
// larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); }} //如下三个方法实现了Array扩容的操做 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++;//扩容一定致使此值++ // overflow-conscious code if (minCapacity - elementData.length > 0)//目标长度>现有长途条件下 grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容容量为旧容量的1.5倍,增加因子为1/2 if (newCapacity - minCapacity < 0)//若是以后容量仍是不够用 newCapacity = minCapacity;//扩容到目标容量 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);//此方法最总会调用System.ArrayCopy() } public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } //System类中的静态方法,这是一个native方法. //经过此方法实现复制出新数组,实现数组的扩容(其是对对象引用的复制-浅度复制) public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)复制代码
int modCount: 每次数组结构改变都会modCount++(增长致使扩容,或者删)数组
private int size; 集合数据的长度-list.size()获取的值bash
transient Object[] elementData;真正的存储东西的元素数组. 长度会>= sizedom
修饰词:transient,不参与序列化。 通常数组的容量会大于所存元素的个数,因此不必所有参与序列化,浪费多余空间.在writeObject()中序列化真正存储数据的元素就能够了.复制代码
数组的结构改变标识为modCount的值改变了ide
System.arraycopy()
是一个native的数组之间复制的操做,由集合中的grow(minCapacity) 方法控制函数
👇是ArrayList的增删改查方法里,☝两个关键数据的变化的状况ui
##1.增---public boolean add(E e)
`modCount++
if (minCapacity - elementData.length > 0)`----若是新集合长度>如今数组长度 会`grow(minCapacity)`;复制代码
##2.删---remove(Object o)this
`modCount++
grow(minCapacity);`复制代码
##3. 改---set(int index, E element)spa
两个操做都没发生复制代码
##4.查---contains(Object o) ,indexOf(Object o)code
两个操做都没发生复制代码
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;//将modCount的值记录下来
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();//每次都会先检查是否发生过结构改变(modCount值是否相同)
int i = cursor;
if (i >= size) throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}}复制代码
增,删,改,查等每次都会先检查是否索引越界
增删数组确定会修改modCount的值
System.arrayCopy()发生条件:a集合增长致使扩容,b删除元素。而集合的改查不会发生数组拷贝
结合安卓加载数据使用场景, 列表展现经常使用,查是高频操做,增删较少,因此ArrayList最合适 复制代码
zyt