一.成员变量
// 在AbstractList里面定义的
protected transient int modCount = 0;
// 内部用数组实现
private transient Object[] elementData;
private int size;
二.构造函数
// 自己在写代码的时候为了严谨,最好是先判断参数抛出IllegalArgumentException
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "
+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
// 初始化容量10
public ArrayList() {
this(10);
}
三.存数据
//增加数据
public boolean add(E e) {
//1.保证容量,size+1和容量比较,看是否有位置插入e
ensureCapacity(size + 1); // Increments modCount!!
//2.直接赋值
elementData[size++] = e;
return true;
}
//在指定位置增加数据
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
+ size);
//1.保证容量
ensureCapacity(size + 1); // Increments modCount!!
//2.向右移动当前位于该位置的元素(如果有)以及所有后续元素(将其索引加 1)。
System.arraycopy(elementData, index, elementData, index + 1, size
- index);
//3.将指定的元素插入此列表中的指定位置
elementData[index] = element;
size++;
}
// 检查容量,minCapacity=size+1
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
// 如果超过容量
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
// 新容量=(老容量 * 3)/2 + 1
// 如果老容量为10,则新容量为16
int newCapacity = (oldCapacity * 3) / 2 + 1;
//newCapacity < minCapacity会产生这样的情况?????
if (newCapacity < minCapacity)
newCapacity = minCapacity;
//复制原数组数据到大小为newCapacity的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
//替换数据
public E set(int index, E element) {
RangeCheck(index);
//保存index处旧值
E oldValue = (E) elementData[index];
//赋新值
elementData[index] = element;
return oldValue;
}
//下标志检查
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
+ size);
}
四.取数据
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
// 返回第一次出现o的下标,用equals比较
// 如果不存在o,返回-1
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i] == null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
// 想想为什么不这么实现
// 上面的实现方式比较次数2+n,下面的比较次数2*n
public int indexOf(Object o) {
for (int i = 0; i < size; i++) {
if (o == null) {
if (elementData[i] == null)
return i;
} else {
if (o.equals(elementData[i]))
return i;
}
}
return -1;
}
// 从size-1往0遍历
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size - 1; i >= 0; i--)
if (elementData[i] == null)
return i;
} else {
for (int i = size - 1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
五.删数据
//移除index处的元素是List接口里新加的方法
//同Map一样,在插入元素的操作中会扩容,删除元素并不去减容
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
//需要移动的元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
//数组内(间)元素移动,五个参数依次为
//src - 源数组。
//srcPos - 源数组中的起始位置。
//dest - 目标数组。
//destPos - 目标数据中的起始位置。
//length - 要复制的数组元素的数量。
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
//让GC回收因移动空出的数组最后一位
elementData[--size] = null;
return oldValue;
}
//remove某个元素是Collection接口里的方法
//同Map一样,在插入元素的操作中会扩容,删除元素并不去减容
//remove(int index)和remove(Object o)一次只会移除一个元素
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;
}
//把index后的元素移往前移一位
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
//让GC回收因移动空出的数组最后一位
elementData[--size] = null;
}
六.List与Array
//ArrayList转换成数组
//将ArrayList内部的数组0到size-1位返回即可
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
//ArrayList转换成指定数组a
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}