目录
前言
一、ArrayList继承关系及全部源码
?1、继承关系
?2、构造函数及方法列表?
?二、分段解读1.ArrayList属性
2.构造函数
2.1 无参构造函数
2.2 参数为数字类型的构造函数
2.3、参数为集合的构造函数
3、添加方法
3.1 add(E e)
3.2 add(int index, E element)
3.3?addAll(Collection c)
3.4?addAll(int index, Collection c)
4、删除
4.1 remove(int index)
4.2? remove(Object o)
4.3?removeAll(Collection c)
4.4?retainAll(Collection c)?
4.6?removeIf(Predicate filter)
4.6?removeRange(int fromIndex, int toIndex)?
4.7?clear()
6、查询
6.1?get(int index)?
6.2? indexOf(Object o)
6.3?lastIndexOf(Object o)
6.4 contains(Object o)
7、其他
7.1?trimToSize()
7.2??ensureCapacity(int minCapacity)
7.3 size()
?7.4?isEmpty()
7.5 clone()
?7.6? toArray()
7.7? toArray(T[] a)
7.8 iterator()
总结
前言
?为了复习Java集合相关知识点,对相关Java 集合源码进行走读学习,本篇文章记录对ArrayList(JDK1.8)源码走读的记录
一、ArrayList继承关系及全部源码
?1、继承关系
?2、构造函数及方法列表?
二、分段解读
1.ArrayList属性
?
//序列号
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity. 默认初始化容量
*/
//默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances. 共享空数组用于空实例
* 用于空实例的共享空数组
*/
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
* 用于默认大小的空实例的共享空数组实例。我们将其与EMPTY_ELEMENTDATA分开来,以了解添加第一个元素时要扩充多少。
*/
//空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
* 存储ArrayList元素的数组缓冲区。ArrayList的容量是此数组缓冲区的长度。
* 任何 elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的ArrayList 在第一次添加元素时容量都将被扩容到默认初始话容量
*
*/
// 就是存储ArrayList元素的数组,这也就是说ArrayList用数组来存储元素的
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
* ArrayList的大小(它包含的元素数)。
*
* @serial
*/
private int size;
DEFAULTCAPACITY_EMPTY_ELEMENTDATA与EMPTY_ELEMENTDATA?都是一个空数组,区别就是使用的地方不一样,DEFAULTCAPACITY_EMPTY_ELEMENTDATA属性是在无参构造函数创建对象时被使用,而EMPTY_ELEMENTDATA则使用在集合容量为0是被使用。?
size 指的是当前集合中存在的元素个数
elementData.length() 指的是该容器,容量的大小
2.构造函数
2.1 无参构造函数
/**
* Constructs an empty list with an initial capacity of ten.
* 构造一个初始容量为10的空列表。
*/
//空参构造函数
public ArrayList() {
//如果只是用空参的构造函数创建了一个ArrayList对象,其实此时集合容量为0,
//即elementData为一个空容量的数组
//因为DEFAULTCAPACITY_EMPTY_ELEMENTDATA就是一个空容量的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
无参构造函数创建一个容量为0的集合,此时elementData引用了DEFAULTCAPACITY_EMPTY_ELEMENTDATA对象,当第一次向ArrayList添加数据时容器会扩容至默认容量 10
2.2 参数为数字类型的构造函数
/**
* Constructs an empty list with the specified initial capacity.
* 构造具有指定初始容量的空列表。
* @param initialCapacity the initial capacity of the list 列表的初始容量
* @throws IllegalArgumentException if the specified initial capacity
* is negative 如果指定的初始容量为负
*/
//有参构造函数,参数为创建集合时要集合容量的大小
public ArrayList(int initialCapacity) {
//判断参数是否大于0
if (initialCapacity > 0) {
//如果参数大于0,则创建指定大小的数组,并赋值给 elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果参数等于0 则 将空数组赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
//如果参数对上边两个判断都不满足则报异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
该构造函数参数为要创建的ArrayList集合的容量大小,如果大于0则创建指定大小的数组对象,并把对象的引用赋值给成员属性elementData,如果参数为0则把EMPTY_ELEMENTDATA对象赋值给elementData,此时集合容量为0,如果参数小于0则会抛出IllegalArgumentException异常
2.3、参数为集合的构造函数
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator. 构造包含指定集合的元素的列表, 按照集合迭代器返回的顺序。
*
* @param c the collection whose elements are to be placed into this list 要将其元素放入此列表的集合
* @throws NullPointerException if the specified collection is null 如果指定的集合为null,则报NullPointerException
*/
public ArrayList(Collection<? extends E> c) {
//将构造方法中的参数转成数组,如果参数为空则会报NullPointerException异常
elementData = c.toArray();
//elementData长度值赋给size,也就是说此时ArrayList它包含的元素数为传过来集合转换为数组的长度
//判断elementData.length是否不等于0
if ((size = elementData.length) != 0) {
//如果不等于0,并且这个数组的类型不是Object[],那么将他转化成Object[]
// c.toArray might (incorrectly) not return Object[] (see 6260652) 这句话大概的意思是c.toArray()有可能返回的不是Object[] 类型
//加上这个判断可以及转换就是为了解决这个bug
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//如果elementData.length等于0则 elementData元素被赋值为 EMPTY_ELEMENTDATA
// replace with empty array.
// 替换为空数组。
this.elementData = EMPTY_ELEMENTDATA;
}
}
?该构造函数的参数为集合,该集合的元素将会全部添加到新建的 ArrayList 实例中。构造函数中会将参数toArray转换成数组,并把对象引用赋值给成员属性elementData,接下来会对elementData.length进行判断,如果为0则说明传入的参数容量为空,则此时会将EMPTY_ELEMENTDATA赋值给elementData,此时创建的ArrayList容量为0。如果不为0,则判断?elementData.getClass() != Object[].class是否为true,如果为true则会进行转换,把数组转化成Object[]。至于为什么要进行判断转换则点击此处查看原因。
3、添加方法
3.1 add(E e)
/**
* Appends the specified element to the end of this list.
* 将指定的元素附加到此列表的末尾
* @param e element to be appended to this list 参数是要加入这个集合的元素
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
//
public boolean add(E e) {
//ensureCapacityInternal方法是确保容器数组有空间,
//特别是传参为size+1,既能保证添加这个新元素数组不溢出,又不会导致空间浪费
ensureCapacityInternal(size + 1); // Increments modCount!!
//size为ArrayList中包含的元素数,
//数组是0从0下标开始的所以传进来的元素放在elementData[size]的位置
//size++表示元素e添加成功后,集合中的元素数又多了一个
elementData[size++] = e;
//如果添加成功则返回true
return true;
}
//参数为数字类型,指定的最小容量
private void ensureCapacityInternal(int minCapacity) {
//判断elementData与DEFAULTCAPACITY_EMPTY_ELEMENTDATA两个对象是否相等
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果相等,则取DEFAULT_CAPACITY与minCapacity当中的最大值
//DEFAULT_CAPACITY为10,minCapacity是动态的
//只有用空参构造函数创建的集合才会相等
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//modCount是记录集合被修改的次数,这里的修改指的是增删改
//modCount是AbstractList中定义的字段
//集合修改次数加1
modCount++;
//防止溢出代码:确保指定的最小容量 > 集合的当前容量
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//minCapacity>elementData.length则说明容量不够需要扩容
grow(minCapacity);
}
/**
* The maximum size of array to allocate. 要分配的最大数组大小。
* Some VMs reserve some header words in an array. 有些虚拟机在数组中保留一些头字
* Attempts to allocate larger arrays may result in 尝试分配较大的阵列可能会导致 OutOfMemoryError
* OutOfMemoryError: Requested array size exceeds VM limit 请求的数组大小超过VM限制
*/
//减去8 是因为Some VMs reserve some header words in an array 有些虚拟机在数组中保留一些头字
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
* 增加容量,以确保它至少可以容纳最小容量参数指定的元素数。
* @param minCapacity the desired minimum capacity 所需的最小容量
*/
private void grow(int minCapacity) {
// overflow-conscious code
//获取elementData数组的大小,并赋值给变量oldCapacity
int oldCapacity = elementData.length;
// >> : 右移,右移几位就相当于除以2的几次幂
// << : 左移,左移几位就相当于乘以2的几次幂
//扩容的核心算法: 原容量的1.5倍
//定义扩容后的容量,并把数值赋值变量newCapacity,newCapacity为oldCapacity的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
// 若 newCapacity 依旧小于 minCapacity,则newCapacity重新赋值为minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果newCapacity 大于MAX_ARRAY_SIZE,则调用hugeCapacity重新赋值
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
//如果minCapacity小于0直接报异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果参数minCapacity大于MAX_ARRAY_SIZE,则返回Integer.MAX_VALUE,否则就直接返回MAX_ARRAY_SIZE
//从MAX_ARRAY_SIZE定义来看 Integer.MAX_VALUE 比 MAX_ARRAY_SIZE 大 8
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
? add(E e) 方法作用实在容器最后元素的后边添加一个新元素e,注意这边指的是容器最后元素的后边,而不是指的是容器成员数组elementData的最后一个位置。add方法中的逻辑是调用ensureCapacityInternal方法,参数为集合中已有元素的个数加1即size+1。ensureCapacityInternal方法一切正常后,就会在?elementData[size] 的位置放入新元素e,至于为什么是放在size这个位置是因为数组下标是从0开始的。元素添加成功后,数组中存在的元素个数要加1即size++,而源码中把添加元素和size自增放在了一起即? elementData[size++] = e,至此元素添加成功,方法返回true。
ensureCapacityInternal方法首先会判断elementData与DEFAULTCAPACITY_EMPTY_ELEMENTDATA两个对象是否相等,如果相等则说明该ArrayList对象是通过无参构造函数创建,因为在无参构造函数中 进行了this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA操作,如果判断相等则取DEFAULT_CAPACITY与参数minCapacity当中的最大值,并把最大值赋给minCapacity,当用无参构造函数创建的对象,并第一次调用add(E e) 方法时这一步 参数minCapacity 为1,而DEFAULT_CAPACITY为10 则minCapacity会重新被赋值为10,这也就是为什么说无参构造函数会创建一个容量为10的集合。
接着ensureCapacityInternal方法会继续调用ensureExplicitCapacity,参数还是为minCapacity。
ensureExplicitCapacity方法,首先会对modCount进行一个自增,modCounts是记录集合被修改的次数,对容器数据的增删改都算对集合进行修改,modCount是AbstractList中定义的字段。modCount自增后,接种会继续判断newCapacity- elementData.length 是否大于0,minCapacity代表着容器现在所需的最小容量,而elementData.length代表着容器实际的容量,如果minCapacity大于elementData.length则说明容量不够需要扩容,反之则不需要扩容。如果不需要扩容则流程结束,如果需要扩容则调用grow()方法。
grow方法作用是扩容,获取elementData数组的大小,并赋值给新定义的变量oldCapacity,接着再定义一个int变量newCapacity,并把oldCapacity的1.5倍数赋值给newCapacity这就是说要把集合容量扩容至原来容量的1.5倍,接下来会对newCapacity与minCapacity(容器现在所需的最小容量)进行比较,如果newCapacity小于minCapacity则说明如果扩容至原来集合容量的1.5倍还是不满足实际需要,那么此时newCapacity会重新赋值为minCapacity。接下来程序会继续拿newCapacity 拿?MAX_ARRAY_SIZE进行比较,MAX_ARRAY_SIZE值为?Integer.MAX_VALUE - 8,减8是因为有些虚拟机在数组中保留一些头字。若newCapacity大于MAX_ARRAY_SIZE,则调用hugeCapacity方法获取?Integer.MAX_VALUE,并把该值重新赋值给newCapacity,至此newCapacity为真正为容器扩容后的容量大小。
接着程序会调用Arrays.copyOf()方法进行扩容。
3.2 add(int index, E element)
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
* 在此列表中的指定位置插入指定元素。 将当前在该位置的元素(如果有)和 后边元素向右移动一位。
* @param index index at which the specified element is to be inserted元素要插入的位置
* @param element element to be inserted 要添加的元素
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
//检查索引是否越界
rangeCheckForAdd(index);
//如果不越界则调用ensureCapacityInternal方法
ensureCapacityInternal(size + 1); // Increments modCount!!
//将当前在该位置的元素(如果有)和 后边元素向右移动一位。
//elementData 源数组。
//index 源数组中的起始位置。
//elementData 目标数组。
//index + 1 目标数据中的起始位置。
//size - index 要复制的数组元素的数量。
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//把元素存在index的位置上
elementData[index] = element;
//集合元素个数加1
size++;
}
/**
* A version of rangeCheck used by add and addAll.
* add 和 addAll 使用的 rangeCheck 版本
*/
private void rangeCheckForAdd(int index) {
//如果index大于size或者小于0,则报异常
//index大于size也报异常,是为了让元素在容器中按照顺序依次保存数据并且避免数组下标越界
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
* 构造一个 IndexOutOfBoundsException 详细消息。
* 在错误处理代码的许多可能重构中,这种“概述”在服务器和客户端 VM 上表现最佳
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
add(int index, E element)方法作用是在容器的指定位置插入指定元素,该方法首先会调用rangeCheckForAdd对要插入的位置进行判断是否下标越界,如果是则直接报异常,否则ensureCapacityInternal方法,ensureCapacityInternal方法与上边的一样这边就不在解释。调用ensureCapacityInternal后,就调用system.arraycopy方法把index位置的元素(如果有)和 后边元素向右移动一位。移动完成后把元素存在index的位置上,并把集合元素个数加1,至此该方法结束,该方法没有返回值
3.3?addAll(Collection<? extends E> c)
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the
* specified collection's Iterator. The behavior of this operation is
* undefined if the specified collection is modified while the operation
* is in progress. (This implies that the behavior of this call is
* undefined if the specified collection is this list, and this
* list is nonempty.)
* 按照指定集合的??迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾。
* 如果在操作进行时修改了指定的集合,则此操作的行为未定义。
*(这意味着如果指定的集合是这个列表,并且这个列表是非空的,那么这个调用的行为是未定义的。)
*
* @param c collection containing elements to be added to this list
* 参数: 要添加到此列表的元素的集合
* @return <tt>true</tt> if this list changed as a result of the call
* 返回 如果此列表因调用而更改,则为true
* @throws NullPointerException if the specified collection is null
* 异常: 如果指定的集合为空则抛出NullPointerException
*/
//将参数中的集合数据添加到ArrayList当中,添加的位置为原有元素的后边
public boolean addAll(Collection<? extends E> c) {
//集合转数组
Object[] a = c.toArray();
//获取数组的长度
int numNew = a.length;
//如果有需要则进行扩容,参数是集合原有元素个数加上传过来集合的元素个数
ensureCapacityInternal(size + numNew); // Increments modCount
//a 源数组。
//0 源数组中的起始位置。
//elementData 目标数组。
//size 目标数据中的起始位置。
//numNew 要复制的数组元素的数量。
//拷贝数据到ArrayList中也就是elementData数组中
System.arraycopy(a, 0, elementData, size, numNew);
//集合的元素个数进行更改,改为原来元素个数加上要加入元素的个数
size += numNew;
//numNew如果不等于零,即传过来的集合有数据则返回true
return numNew != 0;
}
addAll方法 作用是把指定集合按照Iterator返回的顺序保存在ArrayList中,保存位置为ArrayList已有元素的后边。整体流程是先把传过来的集合转成数组,然后获取数组长度并赋值给新定义的局部变量numNew,接着调用ensureCapacityInternal方法进行扩容(如果有需要),ensureCapacityInternal调用完成后进行数据拷贝,把传参数据拷贝到ArrayList中,接着修改集合元素个数即size,改为原来元素个数加上要加入元素的个数的和,接着返回numNew != 0值,如果numNew为0即传来参数为空集合则返回false,反之返回true.
3.4?addAll(int index, Collection<? extends E> c)
/**
* Inserts all of the elements in the specified collection into this
* list, starting at the specified position. Shifts the element
* currently at that position (if any) and any subsequent elements to
* the right (increases their indices). The new elements will appear
* in the list in the order that they are returned by the
* specified collection's iterator.
* 从指定位置开始,将指定集合中的所有元素插入此列表。
* 将当前在该位置的元素(如果有)和任何后续元素向右移动(增加它们的索引)。
* 新元素将按照指定集合的??迭代器返回的顺序出现在列表中
* @param index index at which to insert the first element from the
* specified collection 从指定集合中插入第一个元素的索
* @param c collection containing elements to be added to this list
* 包含要添加到此列表的元素的集合
* @return <tt>true</tt> if this list changed as a result of the call
* 如果此列表因调用而更改,则为true
* @throws IndexOutOfBoundsException {@inheritDoc}
* 如果索引超出范围( index < 0 || index > size() )则抛出IndexOutOfBoundsException
* @throws NullPointerException if the specified collection is null
* 如果指定的集合为空(这里的空是指对象为null,而不指是集合元素个数为0)则抛出NullPointerException
*/
public boolean addAll(int index, Collection<? extends E> c) {
//校验索引
rangeCheckForAdd(index);
//集合转数组
Object[] a = c.toArray();
//获取数组的长度
int numNew = a.length;
//如果有需要则进行扩容,参数是集合原有元素个数加上传过来集合的元素个数
ensureCapacityInternal(size + numNew); // Increments modCount
//numMoved代表要移动元素的个数
int numMoved = size - index;
//numMoved大于0则说明ArrayList集合原有元素需要进行移动
if (numMoved > 0)
//对ArrayList集合元素进行移动
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//拷贝数据到ArrayList中也就是elementData数组指定位置中
System.arraycopy(a, 0, elementData, index, numNew);
//集合的元素个数进行更改,改为原来元素个数加上要加入元素的个数
size += numNew;
//numNew如果不等于零,即传过来的集合有数据则返回true
return numNew != 0;
}
addAll(int index, Collection<? extends E> c)方法的作用是在已有的ArrayList集合中的指定位置添加要添加的集合元素,整体逻辑与addAll(Collection<? extends E> c)类似,只是多了校验索引,及对ArrayList的index及后边的元素(如果有)的移动这两步
4、删除
4.1 remove(int index)
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*移除此列表中指定位置的元素。 将任何后续元素向左移动(从它们的索引中减去一个)
* @param index the index of the element to be removed 要删除的元素的索引
* @return the element that was removed from the list 从列表中删除的元素
* @throws IndexOutOfBoundsException {@inheritDoc}
* 如果索引超出范围 报IndexOutOfBoundsException异常
*/
//通过集合的指定位置删除元素,并把该位置后边的元素(如果有)前移
public E remove(int index) {
//检查坐标是否合法
rangeCheck(index);
//集合修改次数加1
modCount++;
//获取指定位置的元素
E oldValue = elementData(index);
//计算要移动的元素,减1是因为数组坐标是从0开始的
int numMoved = size - index - 1;
//如果大于0,说明要删除的元素后边还有元素
if (numMoved > 0)
//移动元素
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
//把删除的元素返回
return oldValue;
}
/**
* Checks if the given index is in range. If not, throws an appropriate
* runtime exception. This method does *not* check if the index is
* negative: It is always used immediately prior to an array access,
* which throws an ArrayIndexOutOfBoundsException if index is negative.
*检查给定的索引是否在范围内。 如果不是,则抛出适当的运行时异常。
* 此方法不检查索引是否为负数:它总是在数组访问之前立即使用,
* 如果索引为负数,则抛出 ArrayIndexOutOfBoundsException
*/
private void rangeCheck(int index) {
//如果index大于等于size则抛出异常
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
?该方法作用是删除集合指定位置的元素,并返回删除的元素
4.2? remove(Object o)
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If the list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns <tt>true</tt> if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
//从此列表中删除第一次出现的指定元素(如果存在)。
//如果列表不包含该元素,则集合保持不变
public boolean remove(Object o) {
//参数是否为空
if (o == null) {
//参数为空,遍历集合进行查找
for (int index = 0; index < size; index++)
//如果找到元素为null的元素,则根据元素的下标删除元素
if (elementData[index] == null) {
//调用fastRemove删除元素
fastRemove(index);
//删除完成后返回true
return true;
}
} else {
//参数不为空,遍历集合进行查找
for (int index = 0; index < size; index++)
//如果找到指定的元素,注意此时是用equals来判读相同的,不是用==
if (o.equals(elementData[index])) {
//调用fastRemove删除元素
fastRemove(index);
//删除完成后返回true
return true;
}
}
//如果所有条件都不满足即没有找到数据并删除则返回false
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
//跳过边界检查并且不返回删除元素的私有移除方法
private void fastRemove(int index) {
//集合修改次数加1
modCount++;
//计算要移动的元素,减1是因为数组坐标是从0开始的
int numMoved = size - index - 1;
//如果大于0,说明要删除的元素后边还有元素
if (numMoved > 0)
//移动元素
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//移动完成后,把集合元素个数减1,
//并集合移动前的最后一个元素的位置置空,这样避免内存泄漏
elementData[--size] = null; // clear to let GC do its work
}
?该方法作用是删除集合中第一次出现的指定元素(如果存在),即如果集合中有多个相同的元素,那么调用该方法只会删除一个元素,其他相同的元素也不会删除。如果元素被删除则返回true,否则返回false,该方法中使用随机获取的方式遍历集合而不是用顺序获取的方式遍历集合,是因为ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象。这就可以提高ArrayListremove(Object o)的效率。
fastRemove方法与remove(int index)方法类似,只是少了边界检查及不用再一次根据下标查找数据并且不返回删除元素,提高效率
4.3?removeAll(Collection<?> c)
/**
* Removes from this list all of its elements that are contained in the
* specified collection.
* 从此列表中删除包含在指定集合中的所有元素
* @param c collection containing elements to be removed from this list
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
* (<a href="Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see Collection#contains(Object)
*/
//从此列表中删除包含在指定集合中的所有元素
public boolean removeAll(Collection<?> c) {
//健壮性检查,如果参数为null,则抛出NullPointerException
Objects.requireNonNull(c);
//调用batchRemove方法删除元素
return batchRemove(c, false);
}
private boolean batchRemove(Collection<?> c, boolean complement) {
//新建一个局部数组变量elementData
//并把成员变量值赋给局部变量elementData
final Object[] elementData = this.elementData;
//定义int类型的局部变量r,w
int r = 0, w = 0;
//定义局部变量modified
boolean modified = false;
try {
//遍历集合
for (; r < size; r++)
//elementData[r]元素是否存传参集合中
//如果complement为true,则只有c.contains(elementData[r])为true
//即elementData[r]元素存在于传过来集合中,则进入if体,
//如果complement为fale则只有c.contains(elementData[r])为false
//即elementData[r]元素不存在于传过来集合中,则进入if体
if (c.contains(elementData[r]) == complement)
//重新对elementData进行数据存放
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
//保持与 AbstractCollection 的行为兼容性,
// even if c.contains() throws.
//即使 c.contains() 抛出
//如果r!=size则说明有异常抛出
if (r != size) {
//拷贝数组也就是r及其后边的元素,依次拷贝到w往后的位置,拷贝的元素个数为size-r
System.arraycopy(elementData, r,
elementData, w,
size - r);
//w变成w+加上size - r,其实也就是此时ArrayList集合真实存在的元素个数
w += size - r;
}
//如果w不等于size,即现在实际元素的个数与原来的元素个数不一致
if (w != size) {
// clear to let GC do its work
//从现在集合实际存在的元素个数位置开始,后边的元素都置为null,
for (int i = w; i < size; i++)
elementData[i] = null;
//集合修改次数,为原来修改次数加上调用本方法实际修改的次数
modCount += size - w;
//size 重新赋值为w即集合现在实际存在的元素个数
size = w;
//集合有修改则modified置为true
modified = true;
}
}
//返回modified
return modified;
}
removeAll(Collection<?> c)作用是把参数c集合中的元素从ArrayList集合中删除,该方法中核心是私有方法batchRemove,在removeAll方法中,complement为false,则c.contains(elementData[r]) 为false,才会进行数据的移动即elementData[w++] = elementData[r]。c.contains(elementData[r])为false代表着elementData[r]数据不存在与参数集合中,则此时进行elementData[w++] = elementData[r]操作会把ArrayList集合不存在于参数c集合中的元素进行重新存放,重新存放的数组中的元素都是在集合c中不存在的元素,这样就可以完成删除。
4.4?retainAll(Collection<?> c)?
/**
* Retains only the elements in this list that are contained in the
* specified collection. In other words, removes from this list all
* of its elements that are not contained in the specified collection.
*
* @param c collection containing elements to be retained in this list
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
* is incompatible with the specified collection
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this list contains a null element and the
* specified collection does not permit null elements
* (<a href="Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @see Collection#contains(Object)
*/
//仅保留此列表中包含在指定集合中的元素。 换句话说,从该列表中删除所有未包含在指定集合中的元素。
public boolean retainAll(Collection<?> c) {
//健壮性检查,如果参数为null,则抛出NullPointerException
Objects.requireNonNull(c);
//调用batchRemove方法删除不存在与c中的元素
return batchRemove(c, true);
}
?retainAll仅保留此列表中包含在指定集合中的元素。 换句话说,从该列表中删除所有未包含在指定集合中的元素。与removeAll方法作用正好相反
4.6?removeIf(Predicate<? super E> filter)
该方法暂不解读
4.6?removeRange(int fromIndex, int toIndex)?
/**
* Removes from this list all of the elements whose index is between
* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
* Shifts any succeeding elements to the left (reduces their index).
* This call shortens the list by {@code (toIndex - fromIndex)} elements.
* (If {@code toIndex==fromIndex}, this operation has no effect.)
* 从此列表中删除其索引介于fromIndex和toIndex之间(不包括在内)的所有元素。
* 将任何后续元素向左移动(减少它们的索引)。 此调用通过(toIndex - fromIndex)元素缩短列表。
*(如果toIndex==fromIndex ,则此操作无效。)
* @throws IndexOutOfBoundsException if {@code fromIndex} or
* {@code toIndex} is out of range
* ({@code fromIndex < 0 ||
* fromIndex >= size() ||
* toIndex > size() ||
* toIndex < fromIndex})
*/
//删除集合从fromIndex(含fromIndex)开始位置到toIndex(不含toIndex)位置的元素
protected void removeRange(int fromIndex, int toIndex) {
//集合修改次数加1
modCount++;
//size-toIndex为要移动的元素个数
int numMoved = size - toIndex;
//数据移动
//该操作就是把elementData数组从toIndex(包括toIndex)位置开始往后的元素
//移动到elementData的fromIndex及其往后的位置上,需要移动元素个数为numMoved个
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
//size - (toIndex-fromIndex)为此时集合应该存在的元素个数
int newSize = size - (toIndex-fromIndex);
//从newSize这个位置往后的元素都要被删除掉
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
//size 重新赋值为newSize即此时集合中元素真正的个数
size = newSize;
}
??removeRange(int fromIndex, int toIndex) 方法的作用就是删除集合从fromIndex(含fromIndex)开始位置到toIndex(不含toIndex)位置的元素,图片为该删除的示意图
4.7?clear()
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
//从此列表中删除所有元素。此调用返回后,列表将为空。
public void clear() {
//集合修改次数加1
modCount++;
// clear to let GC do its work
//把数组中有数据的位置置为null
for (int i = 0; i < size; i++)
elementData[i] = null;
//此时集合元素个数为0
size = 0;
}
?5、修改
5.1?set(int index, E element)
/**
* Replaces the element at the specified position in this list with
* the specified element.
* 用指定的元素替换此列表中指定位置的元素
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
//用指定的元素替换此列表中指定位置的元素
public E set(int index, E element) {
//校验索引
rangeCheck(index);
//根据索引取出元素 --> 被替换的元素
E oldValue = elementData(index);
//把element存入到elementData数组中
elementData[index] = element;
//返回被替换的元素
return oldValue;
}
6、查询
6.1?get(int index)? ?
/**
* Returns the element at the specified position in this list.
* 返回此列表中指定位置的元素
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
//返回此列表中指定位置的元素
public E get(int index) {
//校验索引
rangeCheck(index);
//调用elementData()方法返回该位置的元素
return elementData(index);
}
// Positional Access Operations 位置访问操作
@SuppressWarnings("unchecked")
E elementData(int index) {
//返回elementData数组index位置的元素
return (E) elementData[index];
}
6.2? indexOf(Object o)
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
//返回此列表中指定元素第一次出现的索引,如果此列表不包含该元素,则返回 -1
//查找顺序是从0位置开始依次加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;
}
//如果没有找到则返回-1
return -1;
}
6.3?lastIndexOf(Object o)
/**
* Returns the index of the last occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the highest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
//返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回 -1
//查找顺序是从数组最后一个元素位置开始,依次减1
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;
}
//如果没有找到则返回-1
return -1;
}
6.4 contains(Object o)
/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return <tt>true</tt> if this list contains the specified element
*/
//如果此列表包含指定的元素,则返回true
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
7、其他
7.1?trimToSize()
/**
* Trims the capacity of this <tt>ArrayList</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>ArrayList</tt> instance.
*/
//将此ArrayList实例的容量修剪为列表的当前大小。
// 应用程序可以使用此操作来最小化ArrayList实例的存储空间。
public void trimToSize() {
//集合修改次数加1
modCount++;
//判断集合容量是否大于集合元素个数
if (size < elementData.length) {
//如果size等于0即此时集合没有元素则elementData赋值为EMPTY_ELEMENTDATA
//否则重新创建一个数组,大小为size并把元素移到新数组中,并赋值给elementData
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
7.2??ensureCapacity(int minCapacity)
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
* 如有必要,增加此ArrayList实例的容量,以确保它至少可以容纳由最小容量参数指定的元素数量
* @param minCapacity the desired minimum capacity
*/
//增加集合容量,
public void ensureCapacity(int minCapacity) {
//elementData如果等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA则minExpand赋值为0
//否则minExpand为DEFAULT_CAPACITY即为10
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;
//如果minCapacity大于minExpand则进行扩容(如果有需要)
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
?ensureCapacity是为了对集合进行扩容,但这个扩容参数如果小于现有容器的容量则不会扩容
7.3 size()
/**
* Returns the number of elements in this list.
* 返回集合元素个数
* @return the number of elements in this list
*/
//获取集合元素个数
public int size() {
return size;
}
?7.4?isEmpty()
/**
* Returns <tt>true</tt> if this list contains no elements.
*
* @return <tt>true</tt> if this list contains no elements
*/
//判断元素个数是否为0
public boolean isEmpty() {
return size == 0;
}
7.5 clone()
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
//对集合进行浅拷贝,对应的数据不会被复制所以说只是一个浅拷贝
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
//集合修改次数位置0
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
?7.6? toArray()
/**
* Returns an array containing all of the elements in this list
* in proper sequence (from first to last element).
* 以适当的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组
* <p>The returned array will be "safe" in that no references to it are
* maintained by this list. (In other words, this method must allocate
* a new array). The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all of the elements in this list in
* proper sequence
*/
//集合转成数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
此时转成的数组其class类型?仍然为Object[]类型
7.7? toArray(T[] a)
/**
* Returns an array containing all of the elements in this list in proper
* sequence (from first to last element); the runtime type of the returned
* array is that of the specified array. If the list fits in the
* specified array, it is returned therein. Otherwise, a new array is
* allocated with the runtime type of the specified array and the size of
* this list.
*
* <p>If the list fits in the specified array with room to spare
* (i.e., the array has more elements than the list), the element in
* the array immediately following the end of the collection is set to
* <tt>null</tt>. (This is useful in determining the length of the
* list <i>only</i> if the caller knows that the list does not contain
* any null elements.)
*
* @param a the array into which the elements of the list are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing the elements of the list
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this list
* @throws NullPointerException if the specified array is null
*/
@SuppressWarnings("unchecked")
//集合转成 指定的运行时类型的数组
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)
//则数组的size位置置为空,至于为什么这么做,应该是为了确定数组中哪些数据是从集合中复制过来的
//但是这么做,有一个缺陷就是集合中本身没有null元素,否则就没什么意义
a[size] = null;
//返回数组
return a;
}
7.8 iterator()
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
获取集合的迭代器?
总结
?以上就是对ArrayList的大部分代码的走读
|