此处需要注意一个地方,如果oldCapacity + (oldCapacity >> 1)执行的结果超过了int的最大值,即2的31次方减1,那么新数组的长度将变为负数
下面就是比较新数组容量和旧数组的容量,将较大的容量赋值给新数组
如果新数组的容量大小超过了定义的MAX_ARRAY_SIZE大小,那么将调用hugeCapacity()方法
代码如下:
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
传入的容量是负数,考虑到了数值溢出,抛出异常
传入的容量超过了MAX_ARRAY_SIZE大小,则将Integer.MAX_VALUE的值进行返回,否则返回MAX_ARRAY_SIZE
最后调用Arrays.copyOf()方法,将旧数组复制到新数组中,至此便完成了数组的动态扩容
add(int index, E element)
源代码如下所示:
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++; }基于add()方法的分析,分析如下:
判断索引是否越界
复制数组,进行移动
将传入参数赋值给指定下标的数组元素
集合长度加1
rangeCheckForAdd()方法源代码如下所示:
private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }分析如下:
索引的上限是实际元素的长度,下限是0
超过这两个边界值就会抛出异常
注意:由于此处判断范围上限取的实际元素的个数,那么就会造成一个情况,我们使用指定容量的构造方法,创建了一个ArrayList对象,然后使用add(int index, E element)方法时,当添加的index不是0时,就会报错
举例如下:
public static void main(String[] args) { List<String> a = new ArrayList<>(12);// 初始化指定了数组的容量为12 a.add(5, "element"); } //结果如下: // Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 5, Size: 0 // at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:661) // at java.util.ArrayList.add(ArrayList.java:473) // at test.TestAddArrayList.main(TestAddArrayList.java:11)get(int index)
源代码如下所示:
public E get(int index) { rangeCheck(index); return elementData(index); } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } E elementData(int index) { return (E) elementData[index]; }简要分析:
首先判断索引是否在正确的范围之内,此处仅仅只是判断了上限为实际元素个数
超过上限时的报错提示信息为 "Index: "+index+", Size: "+size
当index为负数时的报错提示信息则是:index,仅仅只是显示你访问的index值
调用elementData()方法,直接返回对应索引位置的元素
remove(int index)
源代码如下所示:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); 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; }分析:
首先对index进行判断是否在正确的范围内
移除元素使得数组长度发生了变化,所以modCount++
计算需要移动的元素个数
调用arraycopy()方法进行数组元素的复制和移动
将数组实际长度的最后一位元素赋值为null,方便GC进行回收
最后返回索引位置的元素
不难看出,移除元素实际上也是数组的复制和移动。
indexOf(Object o)