ArrayList
程序员文章站
2022-05-14 12:21:50
...
[align=center][size=large]ArrayList[/size][/align]
一、总结
1.基于 JDK 1.8 源码分析
2.默认初始化长度 10
3.线程不安全,modCount ,对集合的实际操作次数与预期操作次数进行比较,若不同,快速失败,抛出异常;集合通过Iterator 遍历时使用
4.扩容,数组原长度*3/2 + 1
5.ArrayList 与 Array 转换
ArrayList.toArray
Arrays.asList
使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()
二、类声明
1.继承 AbstractList
2.实现 List
3.实现 RandomAccess
三、成员变量及构造方法
四、方法分析
1.
2.
3.
4.
5.
6.
7.
8.
9.toArray()
1.使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()。
说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。
例子:
2.直接使用toArray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误
参考:《阿里巴巴Java开发手册》 1.3.0 版本
一、总结
1.基于 JDK 1.8 源码分析
2.默认初始化长度 10
3.线程不安全,modCount ,对集合的实际操作次数与预期操作次数进行比较,若不同,快速失败,抛出异常;集合通过Iterator 遍历时使用
4.扩容,数组原长度*3/2 + 1
5.ArrayList 与 Array 转换
ArrayList.toArray
Arrays.asList
使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()
二、类声明
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
1.继承 AbstractList
2.实现 List
3.实现 RandomAccess
三、成员变量及构造方法
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
// transient 非序列化
// ArrayList 本质是一个 Object 类型的数组
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
// size 是 ArrayList 包含元素的个数,而不是当前数组的长度
private int size;
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @exception IllegalArgumentException if the specified initial capacity
* is negative
*/
// 指定初始化的数组的大小
public ArrayList(int initialCapacity) {
super();
// 判断初始化长度小于0,非法,抛出异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
// 默认长度10
public ArrayList() {
this(10);
}
/**
* 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 = c.toArray();
size = elementData.length;
// 此处判断,是否为 Object 类型的集合,若是,直接返回;否则进行拷贝
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
// 数组集合拷贝
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
// 新建一个泛型数组,返回值与原集合无关
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;
}
四、方法分析
1.
/**
* 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.
*/
// 若集合中元素的数量原小于集合的大小,浪费存储空间,调用此方法;
// 将集合的大小改为集合中实际元素的数量
public void trimToSize() {
modCount++; // 快速失败,若同时多个线程操作,则抛出异常
// ArrayList 线程不安全
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
2.
/**
* 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
*/
// 数组容量扩容
public void ensureCapacity(int minCapacity) {
modCount++;
// 当前数组的长度(非集合中元素的数量)若小于指定的最小容量
// 则扩容,扩容的长度为 原数组的长度 * 1.5 + 1
// 若扩容后的长度依然小于最小长度,则数组长度为指定的最小长度
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
3.
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
// 集合中包含的元素的数量
public int size() {
return size;
}
/**
* Returns <tt>true</tt> if this list contains no elements.
*
* @return <tt>true</tt> if this list contains no elements
*/
// 是否为空,判断集合中是否有元素,而不是判断集合的大小
public boolean isEmpty() {
return size == 0;
}
4.
/**
* 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 ,否则 false ;
// 即查找指定的元素在集合中的位置,若存在,则返回,若不存在,则返回-1
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* 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.
*/
public int indexOf(Object o) {
// 判断 o 是否为 null , 遍历集合 使用 == ,否则,使用 equals
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;
}
/**
* 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.
*/
// 从数组的尾部开始查找元素的位置
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;
}
5.
/**
* 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
*/
// 克隆,为浅拷贝,
// 对于基本数据类型、String,为深拷贝
// 对于引用数据类型为浅拷贝,
// 即拷贝后的集合中的元素与原集合中的元素依然指向同一个堆中的地址引用
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
6.
/**
* 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 (E) elementData[index];
}
/**
* 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 = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
7.
/**
* 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) {
// 判断增加一个元素后是否需要扩容
ensureCapacity(size + 1); // Increments modCount!!
// 扩容后,size++,因为数组是从0开始计数,size位置即添加元素的位置
// size++ 先使用size 确认元素添加的位置,然后 size+1 表示集合中元素数量+1
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) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
// 将index 位置处的元素,拷贝到 index+1 位置,长度为 size - index
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// index 位置赋值
elementData[index] = element;
size++;
}
/**
* 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
*/
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
// 移动元素的数量
int numMoved = size - index;
if (numMoved > 0)
// 将原来的数组中的index位置后的元素向后移动 numMoved 个位置
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
// 在 index 位置拷贝 a 中的元素
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
8.
/**
* 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 = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
// 将 index + 1 到 size - index - 1 位置的元素前移动一位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将末尾处的元素设置为null等待回收
elementData[--size] = null; // 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) {
// 查找元素的指定位置后根据位置删除某个元素
// 注意:若 o 为Integer 类型,使用时会与上面的重载方法冲突,导致不能区分
// 运行时具体调用哪个方法,做一个数据类型的转化,再处理
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 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; // Let gc do its work
}
/**
* Removes from this list all of the elements whose index is between
* <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
* Shifts any succeeding elements to the left (reduces their index).
* This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
* (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
*
* @param fromIndex index of first element to be removed
* @param toIndex index after last element to be removed
* @throws IndexOutOfBoundsException if fromIndex or toIndex out of
* range (fromIndex < 0 || fromIndex >= size() || toIndex
* > size() || toIndex < fromIndex)
*/
// 删除下标在 from 与 to 之间的元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
// 删除元素的数量
int numMoved = size - toIndex;
// 将 toIndex 位置后的元素拷贝到 fromIndex 到 size 的位置上
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
// 当前元素的数量
int newSize = size - (toIndex-fromIndex);
// GC回收空余位置空间
while (size != newSize)
elementData[--size] = null;
}
9.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
*/
// List --> Object []
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/**
* 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
*/
// 将List转化为 T[] 泛型的数组,其中 T[] 为存放List<T> 中存放的元素的容器
// 若T[]的length < size ,则按照 size 的大小初始化数组大小
// 若T[]的length = size ,进行拷贝
// 若T[]的length > size ,将数组size 位置处的值设置为NULL,等待回收;
// 数组下标 0 ~ size - 1 位置存放 size 个元素
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;
}
1.使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一样的数组,大小就是list.size()。
说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。
例子:
List<String> list = new ArrayList<String>(2);
list.add("1");
list.add("2");
String[] array = new String[list.size()];
array = list.toArray(array);
2.直接使用toArray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误
参考:《阿里巴巴Java开发手册》 1.3.0 版本