构造函数:有3个构造函数
1)在jdk源码中ArrayList无参的构造函数,默认初始化大小是10;
2)带有指定大小参数的构造函数
3)带有集合参数的构造函数
一、确定ArrarList的容量
1、若ArrayList的容量不足以容纳当前的全部元素,设置新的容量 = (原始容量 * 3) / 2 + 1。
2、如果扩容后容量还是不够,则直接将minCapacity设置为当前容量。
public void ensureCapacity(int minCapacity) {
// 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的
modCount++;
int oldCapacity = elementData.length;
// 若当前容量不足以容纳当前的元素个数,设置新的容量=“(原始容量x3)/2 + 1”
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
//如果还不够,则直接将minCapacity设置为当前容量
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
二、添加元素
public boolean add(E e) {
ensureCapacity(size + 1); // 确定ArrayList的容量大小
elementData[size++] = e; // 添加e到ArrayList中
return true;
}
将Element添加到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
ensureCapacity(size+1); //确定ArrarList的容量
//将index位置及后面的元素都往后移一位
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element; //将e添加到index位置
size++;
}
三、获取index位置的元素值
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
四、设置index位置的值为element
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
五、删除ArrayList指定位置的元素
public E remove(int index) {
RangeCheck(index); //检查索引index是否合理
modCount++;
E oldValue = (E) elementData[index]; //保存要删除位置的元素
int numMoved = size - index - 1; //得到要移动的元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; //因为都往后移了一位,所以最后一个元素要置空
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 void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0) //从"index+1"开始,用后面的元素替换前面的元素。
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; //将最后一个元素设为nul
}
六、ArrayList是否包含Object(o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
正向查找,返回元素的索引值
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;
}
}
七、返回ArrayList的Object数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
八、将集合c追加到ArrayList中
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); //得到集合实际保存元素的数组
int numNew = a.length;
ensureCapacity(size + numNew); //确定添加集合后ArrayList的容量合理
System.arraycopy(a, 0, elementData, size, numNew); //利用System.arraycopy方法将数组拷贝到ArrayList集合的数组中
size += numNew;
return numNew != 0;
}
分析ArrayList源码比较重要的几点总结:
1、ArrayList是如何确定容量的—->调用ensureCapacity方法。
2、ArrayList是基于数组的,所以获取元素和设置元素都是这样的形式:elementData[index],只需获取到数组索引就可以了。
3、在ArrayList源码中,大量使用了System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。
比如ArrayList的增加、删除、将集合c追加到ArrayList中这三种操作,都使用了这个方法。
4、Arrays类的静态方法:copyOf(T[] original, int newLength)
original - 要复制的数组 ; newLength - 要返回的副本的长度 ; newType - 要返回的副本的类型
比如ArrayList的toArray()方法就使用了Arrays.copyOf方法。