请考虑以下示例代码:
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个字符串分配空间,那么实际发生了什么?
答案 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())