最近在编程时遇到的小问题,就是ArrayList.add(int index, E e)。调用此方法时报了数组越界。
凭借着经验我是这样想的,当我们执行new ArrayList()时,进程为我们新开辟了size为10的数据。既然已经分配了数组,我们当然可以指定一个元素的位置,即调用add(n, e),只要n < size就不会有问题。有点想当然了。
看看ArrayList的add(int index, E element)的实现,
/** * 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++; }
调用add后,会先执行rangeCheckForAdd方法,rangeCheckForAdd的实现如下:
/** * A version of rangeCheck used by add and addAll. */ private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
index会和ArrayList的私有变量size做比较,那问题就是size到底是多少?什么时候会被改写?
JDK1.6和JDK1.7的实现方式发生了变化,我们以1.7为例子,
添加元素成功后会执行size++,删除元素成功会执行size--。也就是说size是元素个数,并不是数组的长度。
当我们new ArrayList()时,默认给个空的数组,并未指定大小的数组。
private static final Object[] EMPTY_ELEMENTDATA = {};
/** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10;
默认长度是10。
长话短说,
当我们调用add(int index, E e)时,index必须小于size。
String case1 = "case1"; String case3 = "case3"; String case4 = "case4"; List<String> list = new ArrayList<String>(); list.add(case1); list.add(case3); list.add(case4); String case2 = "case2"; list.add(n, case2); System.out.println(list);
上面的例子,当n 小于3时才会执行成功,n > 3时就会报数组越界。