ArrayList简介
ArrayList是一个数组队列,底层是这个类的一个成员变量(Object[] elementData ),容量可以实现动态改变。 和数组一样可以实现添加(add方法)、修改(set方法)、删除(remove 方法)、遍历。ArrayList实现了Serializable接口(可以实现对象流的序列化和反序列化)、Cloneable接口、RandomAccess接口(标记接口可以实现随机访问)、List接口,继承了AbstractList。
下面介绍三种ArrayList的遍历方法
使用迭代器遍历
Iterator<Integer> it = arrayList.iterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
foreach循环遍历
for(Integer number : arrayList){
System.out.print(number + " ");
}
引索值遍历
for(int i = 0; i < arrayList.size(); i++){
System.out.print(arrayList.get(i) + " ");
}
注意:迭代器和foreach(底层还是迭代器)不能使用集合的方法修改元素,否则会抛出并发修改异常。具体请参考点击打开链接其中引索值遍历效率最高,因为底层是使用数组的遍历。
源码分析
1常量和变量
private static final long serialVersionUID = 8683452581122892189L;//版本号
private static final int DEFAULT_CAPACITY = 10;//默认数组容量
private static final Object[] EMPTY_ELEMENTDATA = {};//空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认空对象数组,无参构造期中使用
transient Object[] elementData;//定义底层用来缓存数据的对象数组,不可序列化
private int size;//元素的个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组可分配最大容量,有些虚拟机中会给数组保存头部,尝试分配更大的数组会导致内存溢出
2构造方法
根据实际元素个数创建集合
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); } }
无参构造器,创建空集合
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
带Collection类型参数的构造器
public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//将Collection转化为数组并赋值给elementData if ((size = elementData.length) != 0) {//如果转化后的数组长度不为0则进入for语句,否则创建一个空集合 if (elementData.getClass() != Object[].class)//判断元素是否是是Object类型,如果不是则转化为Object类型 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; } }
3常用方法
trimToSize将集合多余的元素(包括null)去除
public void trimToSize() {
modCount++;//从AbstractList继承用来表示集合修改的次数
if (size < elementData.length) {//只有当集合元素的个数<部内数组的长度时(也就是有空元素)
elementData = (size == 0)//三目元算
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
ensureCapacity提升集合的容量以确保可以至少可以装下minCapacity的元素
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
//判断是否为空集合,如果不是则minExpand=0,若果是minExpend=10
if (minCapacity > minExpand) {//如果minCapacity小于minExpand则说明集合的容量够装下minCapacity个元素
ensureExplicitCapacity(minCapacity);//minCapacity大于minExpaind则进行扩容,扩容的方式为10个10个的增加,参考add方法
}
}
grow增加集合容量,ArrayList的核心方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;//获取ArrayList中elementData数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容到1.5倍
if (newCapacity - minCapacity < 0)//判断新数组的容量够不够minCapacity,够了就用mincapacty创建新数组,不够就用1.5倍的那个
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//判断有没有超过最大长度
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
size返回集合元素的个数
public boolean isEmpty() {
return size == 0;
}
isEmpty判断集合是否为空
public boolean isEmpty() {
return size == 0;
}
contains判断集合是否包含指定对象
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
indexOf返回集合中第一次出现指定对象的位置
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;//如果没有次对象则返回-1
}
lastIndexOf返回指定对象在集合中最后一次出现的位置
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;
}
clone重写Object的clone方法,返回一个具有相同元素的副本
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
toArray将结合转化成数组/数组转换成集合可以用asList
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
get获取指定下标的元素
public E get(int index) {
rangeCheck(index);//检查index是否超过size,超过就抛数组下标越界异常
return elementData(index);
}
set用指定对象替换指定下标的元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
add添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1);//扩容
elementData[size++] = e;
return true;
}
add的重载方法,在指定位置插入元素
public void add(int index, E element) {
rangeCheckForAdd(index);//判断是否越界
ensureCapacityInternal(size + 1); // 扩容
System.arraycopy(elementData, index, elementData, index + 1,//将源数组下标为index长度为size-index的连续元素复制到新数组中,从index+1的位置开始复制。
size - index);
elementData[index] = element;
size++;
}
addAll将指定集合添加到集合中
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();//将指定集合转化为数组
int numNew = a.length;//取到a数组的长度
ensureCapacityInternal(size + numNew); //扩容
System.arraycopy(a, 0, elementData, size, numNew);//将a数组从0下标开始numNew个元素复制到elementData数组从size下标开始
size += numNew;
return numNew != 0;
}
addAll重载方法,在指定位置插入指定集合
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew);
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
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);//源数组第index+1个元素开始数量为numMoved,复 制到新数组的index下标开始
elementData[--size] = null; //size个数减一,将最后一个元素设为null
return oldValue;
}
remove重载方法,删除指定元素,只删除第一次
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;
}
clear清除所有元素
public void clear() {
modCount++;
for (int i = 0; i < size; i++)
elementData[i] = null;//将所有元素都设为null
size = 0;
}
removeRange删除指定范围所有元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
removeAll删除指定集合里的所有元素
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);//判断c是否为空
return batchRemove(c, false);
}
batchRemove根据complement值将ArrayList中包含c中元素删除或保留
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;//定义一个r,一个w两个指针同时右移
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)//如果c中不包括elementData[r]这个元素
elementData[w++] = elementData[r];//则直接将位置上的元素赋给w位置上的元素,w自增
} finally {
if (r != size) {//防止抛出异常导致上面r右移过程没有完成
System.arraycopy(elementData, r,elementData, w,size - r);//
w += size - r;
}
if (w != size) {//如果有悲覆盖掉的元素,则将w后面的元素都赋值为null
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;//修改size为w
modified = true;
}
}
return modified;
}
listIterator重载方法,从指定下标创建迭代器
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
iterator创建一个Iterator迭代器
public Iterator<E> iterator() {
return new Itr();
}
Iterator和ListIterator的区别:
https://blog.csdn.net/NGUhuang/article/details/80378804
subList创建一个子集合,并没有创建新的集合
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size); //fromIndex是否小于0,toIndex是否大于size,fromIndex是否大于toIndex
return new SubList(this, 0, fromIndex, toIndex);//创建一个SubList内部类对象
}