以下声明之间有什么区别:
List list1 = new ArrayList();
List list2 = new ArrayList(10);
默认情况下将其分配为10.但是有什么区别吗?
我可以通过list2
向list2.add("something")
添加第11个元素吗?
答案 0 :(得分:6)
以下是第一个例子的source code
public ArrayList() {
this(10);
}
所以没有区别。由于初始容量为10
,无论您是否通过10,它都会以容量10初始化。
我可以通过list2.add("某些")在list2中添加第11个元素吗?
当然,初始容量不是最终容量。因此,当您继续添加超过10个时,列表的大小会不断增加。
如果您想拥有固定大小的容器,请使用Arrays.asList
(或者,对于原始数组,使用Guava中的asList
方法)并考虑java.util.Collections.unmodifiableList()
值得一读Java 8中的这一变化:In Java 8, why is the default capacity of ArrayList now zero?
简而言之,提供初始容量并不会真正改变任何大小的内容。
答案 1 :(得分:4)
您始终可以在列表中添加元素。但是,ArrayList使用的inlying数组使用默认大小10或初始化ArrayList时指定的大小进行初始化。这意味着,如果你是添加第11个元素,必须增加数组大小,这是通过将数组的内容复制到新的更大的数组实例来完成的。这当然需要时间,具体取决于列表/数组的大小。因此,如果您已经知道,您的列表将包含数千个元素,那么如果您已经使用该近似大小初始化列表,则会更快。
答案 2 :(得分:4)
ArrayList
是可自动增长的,如果需要,它们将自行调整大小以添加其他元素。构造函数中的size参数仅用于内部数组的初始大小,并且当您确切知道要使用该数组的内容时,它是一种优化。
指定此初始容量通常是过早优化,但如果您确实需要10个元素的ArrayList
,则应明确指定它,而不是假设默认大小为10.虽然这实际上是默认行为(最高为JDK 7,IIRC),你不应该依赖它 - JDK 8(我已安装的java-1.8.0-openjdk-1.8.0.101-1.b14.fc24.x86_64
检查)默认情况下创建空 ArrayList
。
答案 3 :(得分:2)
其他答案已经解释得很好,但只是为了保持相关性,在JDK 1.7.0_95中:
/**
* Constructs a new {@code ArrayList} instance with zero initial capacity.
*/
public ArrayList() {
array = EmptyArray.OBJECT;
}
/**
* Constructs a new instance of {@code ArrayList} with the specified
* initial capacity.
*
* @param capacity
* the initial capacity of this {@code ArrayList}.
*/
public ArrayList(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity < 0: " + capacity);
}
array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
}
正如评论所提到的,接受无参数的构造函数初始化一个初始容量为零的ArrayList。
这里更有趣的是一个变量(带注释),它自己提供了大量信息:
/**
* The minimum amount by which the capacity of an ArrayList will increase.
* This tuning parameter controls a time-space tradeoff. This value (12)
* gives empirically good results and is arguably consistent with the
* RI's specified default initial capacity of 10: instead of 10, we start
* with 0 (sans allocation) and jump to 12.
*/
private static final int MIN_CAPACITY_INCREMENT = 12;
答案 4 :(得分:1)
你刚刚选择了一个完美的例子。两者实际上都与new ArrayList()
调用this(10)
;相同;但在内部它将定义大小为10的保持数组。另一方的ArrayList#size
方法只返回变量{{ 1}},只有在添加和删除元素后才会更改。此变量也是size
例外的主要原因。所以你不能这样做。
例如,如果您查看ArrayList的代码,您会发现方法ArrayList#add会调用ArrayList#rangeCheck。范围检查实际上只关心IOOB
变量,而不是保存size
数据的数组的实际长度。
因此,您仍然无法在索引List
处插入数据。此时数据数组的内部长度为5
,但由于您未向10
添加任何内容,List
变量仍为size
且当你试图这样做时,你会得到正确的0
。
在初始化IndexOutOfBoundsException
后尝试调用list.size()
,您会注意到返回的尺寸为List
。
答案 5 :(得分:0)
自JDK 1.7更新40以来,ArrayList的初始化已经过优化,并且对此链接中的两种不同行为进行了很好的解释 java-optimization-empty-arraylist-and-Hashmap-cost-less-memory-jdk-17040-update
所以在Java 1.7u40之前没有区别,但从那个版本来看,存在相当大的差异。
这种差异与性能优化有关,并且不会更改List.add(E e)
和ArrayList(int initialCapacity)
的合同。