一、概述
ArrayList就是数组列表,主要用来装载数据,当我们装载的是基本类型的数据int,long,boolean,short,byte…的时候我们只能存储他们对应的包装类,它的主要底层实现是数组Object[] elementData
特点: 查询效率高,增删效率低,线程不安全。使用频率很高。
二、构造器
/**
* 用来存储元素
*/
transient Object[] elementData;
/**
* 调用带参构造初始化时,如果传入参数为0,给elementData赋值
*/
private static final Object[] EMPTY_ELEMENTDATA = {
};
/**
* 调用空参构造初始化时,给elementData赋值
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
/**
* 带参构造,赋值elementData容量为initialCapacity的Object[]数组
*/
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);
}
}
/**
* 无参构造,赋值elementData一个空数组Object[]
* 只有真正对数据进行添加add时,才分配默认DEFAULT_CAPACITY = 10的初始容量。
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
三、数组扩容
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 判断数组是否为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 如果数组为空,返回10
// minCapacity表示当前元素的size + 1
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 这里的形参minCapacity为上面传入的DEFAULT_CAPACITY,即10。
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);
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);
}
- minCapacity元素增加后数组最小容量所需,如果数组未进行初始化,则与DEFAULT_CAPACITY默认数组大小10比较得到最大值。若已经初始化则直接将所需最小容量minCapacity作为暂定扩容大小
- 如果这个最大值大于原有容量,扩容。
- 位移运算获取新计算容量newCapacity,将该容量与最小所需比较得到最大值作为扩容容量。如果最大值大于Integer.MAX_VALUE则使用Integer最大值作为容量
小结: 初始化ArrayList时,最好预估其大致容量,避免频繁扩容操作。
四、新增元素
他有指定index新增,也有直接新增的,在这之前他会有一步校验长度的判断ensureCapacityInternal,就是说如果长度不够,是需要扩容的。
- 直接新增
/**
* 在列表尾部新增元素
*/
public boolean add(E e) {
// 校验长度决定是否扩容
ensureCapacityInternal(size + 1);
// 新增元素
elementData[size++] = e;
return true;
}
- 指定index新增
/**
* 向指定位置插入元素
*/
public void add(int index, E element) {
// 检查index是否大于size或小于0,否则抛出IndexOutOfBoundsException异常
rangeCheckForAdd(index);
// 校验长度决定是否扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 数组拷贝
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 新增元素
elementData[index] = element;
size++;
}
注意: System.arraycopy()方法五个参数:被复制数组、被复制数组开始复制下标、目标数组、目标数组开始接收复制数组元素下标、被复制数组复制元素数量
五、删除元素
删除其实也和新增类似,都是通过System.arraycopy()实现,不论是remove()亦或是removeAll()。循环遍历数组,找到删除元素后修改数组,完成删除操作。在这里就可以总结下ArrayList采用了数组实现,那么它每次结构变更的都需要一笔花销。所以ArrayList适合随机访问使用,不适合结构频繁更改时使用
- 删除指定下标元素
/**
* 删除指定下标元素
*/
public E remove(int index) {
// 检查index是否小于等于size,否则抛出异常
rangeCheck(index);
// 列表修改次数加一
modCount++;
// 记录将要被删除的元素
E oldValue = elementData(index);
// 将要被移动复制的元素的个数
int numMoved = size - index - 1;
// 复制从index+1开始,numMoved长度的数组到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 boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
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
}
六、迭代器
6.1 接口
向后迭代接口Iterator以及向前迭代接口ListIterator,Iterator提供了向后迭代的方法hasNext()判断是否为最后一个元素,next()获取下一个元素以及remove()移除元素的方法。在这个基础上,ListIterator继承接口Iterator,并扩展向前迭代所需的hasPrevious()、previous(),以及替换set()、新增add(),下标获取nextIndex()、previousIndex()
// 向后迭代接口
public interface Iterator<E> {
/**
* 判断是否为最后一个元素
*/
boolean hasNext();
/**
* 获取下一个元素
*/
E next();
/**
* 移除元素
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
*
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
// 向前迭代器接口,扩展了向后迭代器
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
// 获取下标
int nextIndex();
// 获取下标
int previousIndex();
// 移除元素
void remove();
// 替换
void set(E e);
// 新增
void add(E e);
}
6.2 实现(获取迭代器)
/**
* 获取带参向前构造器
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
/**
* 获取无参向前迭代器
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}
/**
* 获取向后迭代器
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* 内部类,向后迭代器
*/
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;
Itr() {
}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
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();
}
}
/**
* 内部类,向前迭代器
*/
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
七、Vector
Vector的实现很简单,就是把所有的方法统统加上synchronized就完事了。