文章目录
ArrayList
学习集合的方法:
- 看继承结构
- 看构造方法
- 看常用方法
吐槽一下:IDEA的UML图表示的有点肤浅,带三角的实线代表继承某个类,而带三角的虚线表示实现某个接口。
ArrayList是AbstractList的子类,实现了3个标识接口(即没有任何方法),
- RandomAccess实现类支持随机访问
- Cloneable实现类支持克隆,需要重写clone方法
- Serializable实现类支持序列化,需要重写readObject,writeObject方法
成员变量
//serialVersionUID是用来验证版本是否一致的
private static final long serialVersionUID = 8683452581122892189L;
//默认容量为10
private static final int DEFAULT_CAPACITY = 10;
//空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList的底层用对象数组实现
transient Object[] elementData; // non-private to simplify nested class access
//元素个数
private int size;
内部类
//实现了Iterator接口,有hasNext,next方法
private class Itr implements Iterator<E>
//实现了ListIterator接口,增加了hasPrevious,previous,previousIndex方法,即逆序遍历的方法,还有nextIndex
private class ListItr extends Itr implements ListIterator<E>
//返回当前列表的部分视图,为什么叫视图呢?我想是因为没有新建一个列表,而是用指针划定范围,故称视图,范围是[),
private class SubList extends AbstractList<E> implements RandomAccess
static final class ArrayListSpliterator<E> implements Spliterator<E>
构造函数
/**
* 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) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
//无参构造器:则创建一个空对象数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 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
*/
//使用指定集合的元素来创建对象数组
public ArrayList(Collection<? extends E> c) {
//将指定集合的元素放进对象数组,再赋值给elementData
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
add,addAll方法
/**
* 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); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* 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(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
/**
* 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
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
/**
* 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
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws NullPointerException if the specified collection is null
*/
//其实与add方法差不多,只是不再默认添加到末尾了,而是指定下标,假设index为0,
//则要移动的元素个数为:size-index,考虑极端情况:添加到末尾的,则是不要移动元素,
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
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;
}
调整数组容量
public void ensureCapacity(int minCapacity) {
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;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
//计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//先判断当前对象数组是否为空对象数组,使用无参构造器创建列表时,对象数组为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//是的话,从最小容量与默认容量中挑出最大值,即从1,10两个数中挑出10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//确保内部容量
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//确保实际容量
private void ensureExplicitCapacity(int minCapacity) {
//modCount采用fast-fail,即并发访问非线程安全对象时,尽快失败,抛出异常
//什么时候modcount会++?就是发生结构性修改的时候,如添加,删除元素时,查询和更新元素不算,将元素置为null也算删除元素
modCount++;
// overflow-conscious code
//最小容量大于比对象数组长度,如10>0,则扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 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
//保存旧容量
int oldCapacity = elementData.length;
//新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量依旧小于最小容量,如0<10
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
elementData = Arrays.copyOf(elementData, newCapacity);
}
//最大化容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}
大量数据插入
/**
* 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.
*
* @param minCapacity the desired minimum capacity
*/
//大量数据插入,使用ensureCapacity来减少扩容的次数,提高效率,前提是我们要提前知道容量的数量级
public void ensureCapacity(int minCapacity) {
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;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
get方法
/**
* 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);
return elementData(index);
}
// Positional Access Operations
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
//需要下标基于0到(元素个数-1)之间
private void rangeCheck(int index) {
if (index < 0 || index >= this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
set方法
/**
* 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);
elementData[index] = element;
return oldValue;
}
remove,removeAll方法
/**
* 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}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//计算要移动的元素个数,即size-index-1,你可以想象删除下标为0的元素,则要移动的元素为size-1
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
return oldValue;
}
/**
* 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++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
//需要重写equals方法
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/**
* 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) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
//只保留与指定集合的交集或删除与指定集合的交集,
//complement为true是只保留与指定集合的交集,如果没有交集,则elementData元素都被置为null
//complement为false则是删除与指定集合的交集
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
//w用来表示交集的个数
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
/*
* 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
}
Arrays.copy方法与System.arrayCopy方法
/**
* Copies the specified array, truncating or padding with nulls (if necessary)
* so the copy has the specified length. For all indices that are
* valid in both the original array and the copy, the two arrays will
* contain identical values. For any indices that are valid in the
* copy but not the original, the copy will contain <tt>null</tt>.
* Such indices will exist if and only if the specified length
* is greater than that of the original array.
* The resulting array is of the class <tt>newType</tt>.
*
* @param <U> the class of the objects in the original array
* @param <T> the class of the objects in the returned array
* @param original the array to be copied
* @param newLength the length of the copy to be returned
* @param newType the class of the copy to be returned
* @return a copy of the original array, truncated or padded with nulls
* to obtain the specified length
* @throws NegativeArraySizeException if <tt>newLength</tt> is negative
* @throws NullPointerException if <tt>original</tt> is null
* @throws ArrayStoreException if an element copied from
* <tt>original</tt> is not of a runtime type that can be stored in
* an array of class <tt>newType</tt>
* @since 1.6
*/
//Arrays.copy方法底层还是用System.arrayCopy方法实现的,
//Arrays.copy方法有新建数组,而直接用System.arraycopy方法则是没有新建数组
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
技巧
IDEA选中多行的方式:alt+shift
可用调试的方式来分析源代码执行逻辑