ArrayList 初始容量和 IndexOutOfBoundsException [重复]
Posted
技术标签:
【中文标题】ArrayList 初始容量和 IndexOutOfBoundsException [重复]【英文标题】:ArrayList initial capacity and IndexOutOfBoundsException [duplicate] 【发布时间】:2012-08-08 03:09:57 【问题描述】:考虑这个示例代码:
List<String> myList = new ArrayList<String>(7);
myList.add(5, "Hello");
myList.removeAll(Collections.singleton(null));
System.out.println(myList.size() + " objects:" );
for (String s : myList)
System.out.println("\t" + s);
myList
初始化为初始容量 7,然后下一行尝试在位置 5 添加字符串“Hello”。这将引发 IndexOutOfBoundsException:
线程“主”java.lang.IndexOutOfBoundsException 中的异常:索引:5,大小:0
我查看了this question 关于“初始容量”在 ArrayList 方面的含义。我知道这个特定的构造函数正在为 7 个 String 元素分配空间,如果我们尝试将 8 个元素添加到列表中,它将不得不分配更多空间。
我不理解的是为什么它不创建一个大小为 7 的“空”列表,每个索引都有空值,类似于我们声明 String[] myArray = new String[7]
时会发生的情况.我记得了解到 ArrayList 是 Java 对动态数组的实现,所以我期待类似的行为。如果我在声明 new ArrayList<String>(7)
时实际上没有分配 7 个字符串的空间,那么实际发生了什么?
【问题讨论】:
这里的容量和大小是完全不同的两件事。您需要添加 7 个占位符元素来执行您正在尝试的操作,而不仅仅是使用 7 的初始容量。ArrayList
不能替代数组。
另见***.com/questions/8896758/…
【参考方案1】:
我不明白的是为什么它没有创建一个大小为 7 的“空”列表,每个索引都有空值,类似于我们声明 String[] myArray = new String[7] 时会发生的情况.
这在某些情况下很有用……而在其他情况下则没有用。通常你有一个上限是你要创建的列表的大小(或者至少是一个猜测),但是你填充它......而你没有 em> 想要有一个大小错误的列表......所以你必须在“设置”值时维护一个索引,然后再设置大小。
我记得了解到 ArrayList 是 Java 对动态数组的实现,所以我期待类似的行为。
不,真的不是。这是一个可以调整大小的列表,并且在幕后使用一个数组。尽量不要把它想象成一个数组。
如果我在声明新的
ArrayList<String>(7)
时实际上没有分配 7 个字符串的空间,那么实际发生了什么?
你做有7个字符串引用的空间。 buffer 大小(即容量)至少为 7,但列表的 logical 大小仍为 0 - 您还没有向其中添加任何内容。这就像你有一张足够长 7 行的纸,但你还没有写任何东西。
如果您想要一个预填充列表,您可以轻松编写一个方法来创建一个:
public static List<T> createPrefilledList(int size, T item)
ArrayList<T> list = new ArrayList<T>(size);
for (int i = 0; i < size; i++)
list.add(item);
return list;
【讨论】:
如果我查看源代码,Object[] elementDate = new Object[7];,这是否意味着它应该有 7 个基于默认值原则的空元素(elementData 是实例变量)? @thinksteep:我不确定你想表达什么观点,或者你在看什么来源。 array 将有 7 个(不是 8 个)空值。但是列表的逻辑大小仍然是0。 是的,7 个空值,并且 OP 试图在索引 5 处插入元素,这是具有空值的有效位置/索引,那么为什么 IndexOutofBoundException?我的假设是,索引处的 null 应替换为“Hello” @JonSkeet:他指的是java.util.ArrayList
的构造函数代码。
@thinksteep:不,就列表而言,它不是有效的位置。这是一个有效的 array 位置,但它大于列表的大小(由 size()
方法报告),此时为 0,因为没有添加任何值。您必须区分列表的容量和逻辑大小。【参考方案2】:
数组的初始容量与其大小(即数组包含的元素数量)之间存在差异。它的大小用于确定您是否尝试访问超出范围的索引。
这是执行此检查的 ArrayList.java
方法:
private void rangeCheckForAdd(int index)
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
如您所见,它与数组的初始容量无关。它仅基于它包含的元素数量。
【讨论】:
index 是 5,我认为是小于 size(7),不是吗? @thinksteep:不,size 为 0。capacity 为 7。 @JonSkeet:知道了。我的脑子是多么的混乱。谢谢。 +1 表示“它的”与“它的”【参考方案3】:初始容量只做一件事:它给出了后备数组应该有多大的建议(不是要求)。从逻辑上讲,在有或没有建议的情况下允许哪些操作或建议是什么之间没有区别。唯一的变化是作为优化建议可能发生或不发生的内部操作。
您只能像这样“添加”到数组中已经存在的位置。位置 5 之前的元素尚不存在,因此会引发异常。来自Javadoc:
抛出: IndexOutOfBoundsException - 如果索引超出范围 (index size())
【讨论】:
以上是关于ArrayList 初始容量和 IndexOutOfBoundsException [重复]的主要内容,如果未能解决你的问题,请参考以下文章