在Java 8中,为什么ArrayList的默认容量现在为零?

据我所知,在Java 8之前, ArrayList的默认容量是10。

令人惊讶的是,对默认(void)构造函数的评论仍然说: Constructs an empty list with an initial capacity of ten.

ArrayList.java

 /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; ... /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 

从技术上讲,如果你承认支持数组的懒惰初始化,它是10 ,而不是零。 看到:

 public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } 

哪里

 /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; 

你所指的只是在所有最初为空的ArrayList对象之间共享的零大小的初始数组对象。 即10的容量懒散保证,也是在Java 7中存在的一个优化。

诚然,施工合同并不完全准确。 也许这是这里混乱的根源。

背景

这里是Mike Duigou的电子邮件

我已经发布了空的ArrayList和HashMap补丁的更新版本。

http://cr.openjdk.java.net/~mduigou/JDK-7143928/1/webrev/

这个修改后的实施不会引入任何一个新的领域 。 对于ArrayList,仅当默认大小创build列表时才会发生后备数组的延迟分配。 根据我们的性能分析团队,大约85%的ArrayList实例是以默认大小创build的,所以这个优化对于绝大多数情况是有效的。

对于HashMap,创造性地使用阈值字段来跟踪所请求的初始大小,直到需要桶数组为止。 在读取方面,使用isEmpty()testing空映射案例。 在写入大小上,使用(table == EMPTY_TABLE)的比较来检测是否需要扩展存储区arrays。 在readObject中,尝试select一个有效的初始容量还有一些工作要做。

来自: http : //mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html

如果用ArrayList完成的第一个操作是传递addAll一个包含十个以上元素的集合,那么任何用于创build初始十元素数组来保存ArrayList内容的努力都会被抛出窗口。 无论何时添加到ArrayList中,都需要testing结果列表的大小是否会超过后备存储的大小; 允许初始支持存储的大小为零而不是十个将导致此testing在列表的生命周期中失败一个额外的时间,其中第一个操作是“添加”,这将需要创build初始十项目数组,但是该成本是less于创build一个永远不会被使用的十项数组的成本。

如前所述,如果有一个“addAll”超载,可能有可能在某些情况下进一步提高性能,这个超负荷指定在目前的列表之后可能有多less项目(如果有的话)会被添加到列表中,用它来影响它的分配行为。 在某些情况下,将最后几项添加到列表中的代码将有一个相当不错的想法,即列表永远不会需要任何空间。 有很多情况下,一个列表将被填充一次,之后从不修改。 如果在代码中知道列表的最终大小将是170个元素,则它具有150个元素和大小为160的后备存储,将后备存储增大到320的大小将是无益的,并将其留在320处或将其修剪为170的效率低于简单地将下一个分配增加到170。

问题是“为什么?”。

内存分析检查(例如( https://www.yourkit.com/docs/java/help/inspections_mem.jsp#sparse_arrays )显示,空(填充空)数组占用大量的内存。

10个对象的默认大小意味着我们在创build时为底层数组分配10个指针(40或80字节),并用空值填充它们。 真正的java应用程序创build数百万个数组列表

引入的修改删除^ W推迟这个内存消耗,直到你实际使用数组列表。

在Java 8中,ArrayList的默认容量是0,直到我们向ArrayList对象中添加至less一个对象。 请参阅下面的代码寻求帮助。

 ArrayList al = new ArrayList(); //Size: 0, Capacity: 0 ArrayList al = new ArrayList(5); //Size: 0, Capacity: 5 ArrayList al = new ArrayList(new ArrayList(5)); //Size: 0, Capacity: 0 al.add( "shailesh" ); //Size: 1, Capacity: 10 public static void main( String[] args ) throws Exception { ArrayList al = new ArrayList(); getCapacity( al ); al.add( "shailesh" ); getCapacity( al ); } static void getCapacity( ArrayList<?> l ) throws Exception { Field dataField = ArrayList.class.getDeclaredField( "elementData" ); dataField.setAccessible( true ); System.out.format( "Size: %2d, Capacity: %2d%n", l.size(), ( (Object[]) dataField.get( l ) ).length ); } Response: - Size: 0, Capacity: 0 Size: 1, Capacity: 10 

经过上面的问题,我经历了Java 8的ArrayList文档。我发现默认大小仍然只有10。

请看下面

JAVA 8中的ArrayList默认大小是stil 10.在JAVA 8中唯一的变化是,如果编码器添加小于10的元素,则剩余的数组列表空白位置不指定为空。 这样说是因为我经历了这种情况,日食让我看到了JAVA 8的这种变化。

你可以通过看下面的截图来certificate这个改变。 在这里你可以看到ArrayList的大小在Object [10]中被指定为10,但是显示的元素数量只有7个。在这里不显示剩余的空值元素。 在下面的JAVA 7中,截图是相同的,仅仅是一个单独的改变,即空值元素也被显示,编码员需要编写处理空值的代码,如果他在迭代完整的数组列表的时候,编码员/开发人员的负责人。

屏幕截图链接。