1 start
2 arrayList 的底层实现
2.1 数据结构
动态数组中,存储数据用的是一段连续的大内存,所以如果我们要在某一个位置添加或者删除一个元素,剩下的每个元素都要相应地往前或往后移动。
2.2 add(),remove()
实现两个方法的底层核心是Arrays.copyOf(),方法返回的数组是新的数组对象,原数组对象仍是原数组对象,不变,该拷贝不会影响原来的数组。
Arrays.copyOf()又由本地方法 System.arraycopy() 实现;
2.2.1 System.arraycopy() 抽象方法
/**
* @param src the source array.
* @param srcPos starting position in the source array.
* @param dest the destination array.
* @param destPos starting position in the destination data.
* @param length the number of array elements to be copied.
* @exception IndexOutOfBoundsException if copying would cause
* access of data outside array bounds.
* @exception ArrayStoreException if an element in the <code>src</code>
* array could not be stored into the <code>dest</code> array
* because of a type mismatch.
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>.
*/
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
2.2.2 add()方法实现
普通添加:
/**
* 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!!
// 设置数组长度属性,加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) {
rangeCheckForAdd(index); // 校验index是否越界
// 使用arrays.copy,更新数组容量
ensureCapacityInternal(size + 1); // Increments modCount!!
// 再次使用arrays.copy,更新数组元素
System.arraycopy(elementData, index, elementData, index + 1,size - index); // index之后元素整体后移
elementData[index] = element; // index位置插入元素
size++; // 数组长度属性加1
}
/**
* A version of rangeCheck used by add and addAll.
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 设置数组真实容量
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 获取数组最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// 设置数组最小容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 数组长度修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
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: Requested array size exceeds VM limit
*/
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
int oldCapacity = elementData.length;
// 容量变为之前的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 还不足,直接采用实际所需长度;
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 = 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;
}
2.2.3 remove()方法实现
指定位置删除:
/**
* 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); // 校验index
modCount++; // 数组结构操作次数,加1
E oldValue = elementData(index); // 获取被删除的元素
// 获取需要移动的元素的数量
int numMoved = size - index - 1;
// 复制数组元素
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
// 数组长度属性减1
// 最后一个元素置空
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
*/
// 从前往后,找到并删除第一个元素,不管null与否
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 remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
// 数组结构操作次数,加1
modCount++;
// 数组元素移动数量
int numMoved = size - index - 1;
// 通过复制,移动元素
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 数组长度属性减1
// 最后一个元素置空
elementData[--size] = null; // clear to let GC do its work
}
2.3 iterator(foreach)遍历
2.3.1 遍历分为两步:
// Iterator iterator = formList.iterator();
// if (iterator.hasNext()) {
// Object next = iterator.next();
//
// }
// 第一步,判断是否有下个元素
public boolean hasNext() {
// 校验当前内存位置是否超出数组地址长度
return cursor != size;
}
// 第二步,下个元素是什么,并赋值给上面例子中的item变量
@SuppressWarnings("unchecked")
public E next() {
// 校验数组数据结构变化次数
checkForComodification();
int i = cursor;
// 地址超出界限,一般不会发生
if (i >= size)
throw new NoSuchElementException();
// 获取整个数组元素
Object[] elementData = ArrayList.this.elementData;
// 地址超出数组长度
if (i >= elementData.length)
throw new ConcurrentModificationException();
// 指向下一个元素的地址
cursor = i + 1;
return (E) elementData[lastRet = i];
}
// 校验底层数组的数据结构变化次数,
// 新增或删除元素是modeCount++,导致iterator遍历时,抛出并发修改异常;
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
2.3.2 ConcurrentModificationException
Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。
避免该异常的办法有两种,1.遍历完在删除;2.iterator.remove();
// Iterator iterator = formList.iterator();
// if (iterator.hasNext()) {
// Object next = iterator.next();
// iterator.remove();
//
// }
Iterator.remove()实现:
// expectedModCount = modCount,保证了两者的相等
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
2.4 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);
}
/**
* 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.
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// Positional Access Operations
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
2.5 substring()
具有相同的底层数组;操作子数组会影响原来的数组;
/**
* Returns a view of the portion of this list between the specified
* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. (If
* {@code fromIndex} and {@code toIndex} are equal, the returned list is
* empty.) The returned list is backed by this list, so non-structural
* changes in the returned list are reflected in this list, and vice-versa.
* The returned list supports all of the optional list operations.
*
* <p>This method eliminates the need for explicit range operations (of
* the sort that commonly exist for arrays). Any operation that expects
* a list can be used as a range operation by passing a subList view
* instead of a whole list. For example, the following idiom
* removes a range of elements from a list:
* <pre>
* list.subList(from, to).clear();
* </pre>
* Similar idioms may be constructed for {@link #indexOf(Object)} and
* {@link #lastIndexOf(Object)}, and all of the algorithms in the
* {@link Collections} class can be applied to a subList.
*
* <p>The semantics of the list returned by this method become undefined if
* the backing list (i.e., this list) is <i>structurally modified</i> in
* any way other than via the returned list. (Structural modifications are
* those that change the size of this list, or otherwise perturb it in such
* a fashion that iterations in progress may yield incorrect results.)
*
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
// 下标校验
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
// 赋值一个子数组,
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
2.4 异常
java.util.ConcurrentModificationException; // 并发修改异常:同时iterator遍历,同时add或remove触发
IndexOutOfBoundsException(); // 下标越界异常:add(index,object),index指定数据越界
new NoSuchElementException(); // 无此数据异常:iterator遍历数组时地址超出界限,一般不会发生;
ArrayStoreException // 数据类型不匹配异常:add时数据类型不匹配;
NullPointerException // 空指针异常:add时,源数组为null;
2.5 error
new OutOfMemoryError(); // 内存益处错误:add数据时,内存溢出;