ArrayList初始容量和IndexOutOfBoundsException

时间:2012-08-10 19:28:04

标签: java string arraylist

请考虑以下示例代码:

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:

  

线程“main”中的异常java.lang.IndexOutOfBoundsException:索引:5,大小:0

我查看了this question关于“初始容量”在ArrayList方面意味着什么。据我所知,这个特殊的构造函数正在为7个String元素分配空间,如果我们尝试在列表中添加8个元素,则必须分配更多的空间。

理解的是为什么它不会创建大小为7的“空”列表,每个索引都有空值,类似于我们声明{{1 }}。我记得我知道ArrayList是Java的动态数组实现,所以我期待类似的行为。如果我在声明String[] myArray = new String[7]时实际上没有为7个字符串分配空间,那么实际发生了什么?

3 个答案:

答案 0 :(得分:22)

  

我不明白为什么它不会创建大小为7的“空”列表,每个索引都有空值,类似于我们声明String [] myArray = new String [7]时会发生的情况

这在某些情况下会有用......而在其他情况下则无用。通常你有一个你将要创建的列表大小的上限(或者至少是一个猜测)但是你填充它...而你不会想拥有一个大小错误的列表......所以你必须在“设置”值时保持一个索引,然后再设置大小。

  

我记得我知道ArrayList是Java的动态数组实现,所以我期待类似的行为。

不,实际上并非如此。这是一个可以调整大小的列表,在幕后使用一个数组。尽量不要将它视为一个数组。

  

如果我在宣布新的ArrayList<String>(7)时实际上没有为7个字符串分配空间,那么实际发生了什么?

有7个字符串引用的空间。 缓冲区大小(即容量)至少为7,但列表的逻辑大小仍为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;
}

答案 1 :(得分:5)

数组的初始容量 size (即数组包含的元素数)之间存在差异。它的大小用于确定您是否正在尝试访问超出范围的索引。

以下是执行此检查的ArrayList.java方法:

 private void rangeCheckForAdd(int index) {
   if (index < 0 || index > this.size)
     throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 }

如您所见,它与阵列的初始容量无关。它完全基于它包含的元素数量。

答案 2 :(得分:2)

初始容量只做一件事:它给出了支持数组应该有多大的建议(不是要求)。从逻辑上讲,无论有无建议,或建议是什么,都没有区别。唯一的变化将是作为优化建议可能发生或不发生的内部操作。

您只能将“添加”添加到数组中已存在的位置。位置5之前的元素尚不存在,因此它会抛出异常。来自Javadoc

  

抛出:   IndexOutOfBoundsException - 如果索引超出范围(索引&lt; 0 || index&gt; size())