为什么我们不能在将元素添加到第(n-1)个索引之前将元素添加到List到第n个索引中,即使提供了初始容量也是如此

问题描述 投票:0回答:3

假设我声明了一个大小为10的int数组,我可以在其第四个索引中添加一个元素,我可以毫无例外地运行代码。

int[] ar = new int[10];
ar[4] = 8;      
System.out.println(Arrays.toString(ar)); //works fine

那是因为当我说大小为10时,将为该数组分配那么多的内存空间,其类型的初始值保存在每个索引中。

List的案例并不相同。假设我声明了一个初始容量为10的列表,并尝试将一个元素添加到它给出的第四个索引中

java.lang.IndexOutOfBoundsException:索引:4,大小:0

List<Integer> list = new ArrayList<Integer>(10);
list.add(4, 8); //exception

当然,即使给出初始容量,列表的大小也将返回0。为什么它不像Array,我认为没有为列表的10个元素分配内存?

我猜测,一旦像数组一样给出容量,有没有办法用List填充默认值。

java arrays list indexoutofboundsexception
3个回答
2
投票

到目前为止,应该很清楚构造函数的初始容量只是初始内部数组的一些内存管理。没有任何语义含义。

当实际的size()溢出数组时,将重新分配该数组。

没有使用初始元素进行批量分配的事情。但是有:

List<Integer> list = Collections.nCopies(10, Integer.valueOf(0));

而新的Stream提供了动态生成列表的方法。

你可以这样做:

public <T> void add(List<T> list, int i, T obj) {
    while (list.size() < i) {
        list.add(null);
    }
    list.add(i, obj);
}

但很明显,你会引入不安全和丑陋的空值,需要空检查。


7
投票

这就是ArrayList的JavaDoc所说的关于add(int index, E element)的内容:

抛出IndexOutOfBoundsException - 如果索引超出范围(索引<0 || index> size())

大小是当前存储的元素数,而不是当前容量。

事实上你的汽车有“容量”以100英里/小时的速度行驶,这并不意味着你可以在1秒内神奇地从0加速到90英里/小时;-)

换句话说:答案是尺寸和容量不一样。容量仅仅意味着:“这是这个列表在底层数组需要增长之前可以增长的大小”。


0
投票

正如其他人在他们的答案中提到的那样,在List<Integer> list = new ArrayList<Integer>(10)中,10指定了初始容量。

指定初始容量只是一个可选项。只有在使用接受初始容量作为参数的特定构造函数时,才能执行该选项。使用其他构造函数时,您无法控制初始容量。

如果您希望列表中的第一个n添加项尽可能高效,则指定n作为初始容量 - 否则,每个单独项目添加到列表中可能会导致一些代价高昂的内部重新调整大小重新复制到重新调整大小的内部区域。

以上内容并未回答为什么在第7位没有任何项目时不允许在第8位添加项目的问题。

有些人回答说,那是因为the API doc says so

这是回答它的一种方法。但为什么API文档会这样说呢?为什么设计这样的东西?

事情的设计是这样的,因为:

  1. 在位置8处添加项目,当位置7处没有项目时,导致间隙(在位置8之前)。
  2. 作为程序员,您必须在所有可能的位置(全部容量)中跟踪项目的位置。目前,作为程序员,您只能跟踪所有添加项目中项目的位置。现在,这不是编程的噩梦吗?
© www.soinside.com 2019 - 2024. All rights reserved.