隐式和显式ArrayList大小声明之间的区别?

时间:2016-08-10 05:56:46

标签: java arraylist collections

以下声明之间有什么区别:

List list1 = new ArrayList();

List list2 = new ArrayList(10);

默认情况下将其分配为10.但是有什么区别吗? 我可以通过list2list2.add("something")添加第11个元素吗?

6 个答案:

答案 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)

Java中的

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)的合同。