ArrayList详解-源码分析 (3)

此处需要注意一个地方,如果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)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgdfpj.html