ArrayList的支持数组的长度与ArrayList的.size()不同

时间:2018-06-15 21:53:08

标签: java android arrays arraylist

在调试应用程序时,在无效索引处访问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}}。

2 个答案:

答案 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实际上并未用作初始大小。您可能已经注意到,使用的初始数组实际上是空的,大小为零,然后根据实际添加的元素数扩展数组。