在调试应用程序时,在无效索引处访问ArrayList
时会引发以下错误:
java.lang.ArrayIndexOutOfBoundsException: length=5; index=-1
at java.util.ArrayList.get(ArrayList.java:439)
无效索引(-1
)是预期的,但出乎意料的是长度为5.正在访问的ArrayList
被验证为.size()
3
深入研究ArrayList
的源代码,可以找到以下内容:
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
// Android-note: Also accessed from java.util.Collections
transient Object[] elementData; // non-private to simplify nested class access
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
似乎在实例化ArrayList
并添加第一项时,默认情况下,支持数组的长度为10
。当上述原始错误显示10
的长度时,这是通过实验验证的(一次)。
但是,在大多数运行中,错误中显示的后备阵列的长度为5
,而正在访问的.size()
的{{1}}仍为ArrayList
。如何将后备阵列的长度修改为3
的长度?特别是在给出源代码的情况下,如果显示除5
的值之外的任何值,则可以预期它为.size()
。
我希望修改内部支持数组以适应其中元素数量的长度,特别是为了抛出10
,因为显示的长度在不匹配时非常混乱ArrayIndexOutOfBoundsException
的{{1}}。
答案 0 :(得分:2)
首先 - 这是正常的。 ArrayList
这样做是为了加快速度。如果底层数组与列表大小匹配,则添加/删除操作会慢得多(每次都需要重新分配数组)。
要回答您的直接问题,有多种方法可以实例化ArrayList
- 特别是通过传递现有Collection
或提供int initialCapacity
。这两个都可以提供比默认值更小的底层数组。
// Source code of other `ArrayList` constructors below (trimmed for clarity to how `elementData` gets initialized)
public ArrayList(int initialCapacity) {
...
this.elementData = new Object[initialCapacity];
...
}
public ArrayList(Collection<? extends E> c) {
...
elementData = c.toArray();
...
}
答案 1 :(得分:1)
这是完全正常的。 ArrayList
的支持数组在调整大小时会扩展为 more ,而不是完全相同的大小。这样就不必在每次添加元素时进行扩展,因为扩展需要O(n)副本,因此添加额外的空间会减少您必须执行的副本数量。
此外,DEFAULT_CAPACITY
实际上并未用作初始大小。您可能已经注意到,使用的初始数组实际上是空的,大小为零,然后根据实际添加的元素数扩展数组。