Java ArrayList的后备数组与ArrayList的长度不同';s.size()
调试应用程序时,访问无效索引处的Java ArrayList的后备数组与ArrayList的长度不同';s.size(),java,android,arrays,arraylist,Java,Android,Arrays,Arraylist,调试应用程序时,访问无效索引处的ArrayList时引发以下错误: java.lang.ArrayIndexOutOfBoundsException: length=5; index=-1 at java.util.ArrayList.get(ArrayList.java:439) 预期索引无效(-1),但意外的是长度为5。正在访问的ArrayList已验证为3的.size() 深入研究ArrayList的源代码,可以找到以下内容: /**
ArrayList
时引发以下错误:
java.lang.ArrayIndexOutOfBoundsException: length=5; index=-1
at java.util.ArrayList.get(ArrayList.java:439)
预期索引无效(-1
),但意外的是长度为5。正在访问的ArrayList
已验证为3的.size()
深入研究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
,而被访问的ArrayList
的.size()
仍然是3
。如何将备份阵列的此长度修改为5
?特别是在给定源代码的情况下,如果显示的值不是.size()
,则应该是10
我希望修改内部支持数组以适应其内部元素数量的长度,特别是为了抛出ArrayIndexOutOfBoundsException
,因为当显示的长度与ArrayList
的.size()
不匹配时,会非常混乱 这是完全正常的。ArrayList
的备份数组在调整大小时,会扩展到比所需大小更精确的大小。这样就不必每次添加元素时都对其进行扩展,因为扩展需要O(n)个副本,因此添加额外的空间可以减少必须执行的副本数量
此外,DEFAULT\u容量
实际上没有用作初始大小。您可能已经注意到,使用的初始数组实际上是空的,大小为零,然后根据实际添加的元素数展开数组。首先,这是正常的ArrayList
这样做是为了更快。如果基础数组与列表大小匹配,则添加/删除操作将慢得多(需要每次重新分配数组)
要回答您的直接问题,有多种方法可以实例化ArrayList
——特别是通过向其传递现有的集合
,或提供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();
...
}
//下面其他'ArrayList'构造函数的源代码(为了清楚说明'elementData'是如何初始化的而进行了修剪)
公共阵列列表(int initialCapacity){
...
this.elementData=新对象[初始容量];
...
}
公共阵列列表(Collection它扩展的大小在不同的执行之间会有所不同吗?我很好奇在不同的运行中如何观察到10
和5
的长度。它不应该这样变化。@Orbit据我所知,当数组增长时,大小应该加倍。这个iGuarante为“O”的insert
操作提供了摊销成本(log(n))。不,通过任何常数乘数>1进行扩展都会得到摊销的O(1)添加。O(log n)扩展将被完成。另一方面,备份数组永远不会自动收缩(尽管用户可以使用trimToSize()
将数组大小显式地与元素数相匹配)。