问题描述
假设我声明了一个大小为10的int
数组,我可以在其第4个索引中添加一个元素,我可以毫无例外地运行代码。
int[] ar = new int[10];
ar[4] = 8;
System.out.println(Arrays.toString(ar)); //works fine
这是因为当我说size为10时,将为该数组分配那么多的内存空间,并且其类型的初始值保留在每个索引中。
但是List
的情况不同。
假设我声明了一个初始容量为10的列表,然后尝试在其第4个索引中添加一个元素
java.lang.IndexOutOfBoundsException:索引:4,大小:0
List<Integer> list = new ArrayList<Integer>(10);
list.add(4, 8); //exception
当然,即使给出初始容量,列表的大小也将返回0
。
为什么它不像Array,我认为该列表没有为10个元素分配内存?
我猜想一旦给定一个容量就像数组一样,有没有办法用默认值填充List。
1楼
这是ArrayList的关于add(int index, E element)
:
抛出IndexOutOfBoundsException-如果索引超出范围(索引<0 ||索引> size())
大小是当前存储的元素数,而不是当前的容量 。
您的汽车具有以100 mph的速度行驶的“能力”这一事实,并不意味着您可以在1秒钟内神奇地将速度从0加速到90 mph ;-)
换句话说:答案是大小和容量不一样。 容量仅表示:“这是在基础数组需要增长之前,此列表可以增长到的大小”。
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);
}
但是很明显,您将引入null ,这是不安全且丑陋的,需要进行null检查。
3楼
正如其他人在其答案中提到的那样,在List<Integer> list = new ArrayList<Integer>(10)
, 10
表示初始容量 。
指定初始容量只是可选的事情。 仅当您使用接受初始容量作为参数的特定构造函数时,才行使该选项。 使用其他构造函数时,您无法控制初始容量。
如果要使列表的前n
添加尽可能高效,则将n
指定为初始容量-否则,将每个项目添加到列表中可能会导致内部调整大小和重新复制到调整后的内部区域中。
上面的内容并没有回答为什么在位置7没有项目时为什么不允许在位置8添加项目的问题。
有人回答说,这是因为 。
那是回答它的一种方式。 但是,为什么API文档这么说呢? 为什么事情是这样设计的?
之所以设计事物,是因为:
- 如果位置7处没有项目,则在位置8处添加项目会导致出现间隙(位置8之前)。
- 作为程序员,您将必须在所有可能的位置(最大容量)中跟踪项目的位置。 当前,作为程序员,您只能跟踪所有已添加项目中项目的位置。 现在,这不是编程的噩梦吗?