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

2022-08-31 10:19:57

我记得,在Java 8之前,默认容量为10。ArrayList

令人惊讶的是,对默认(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;
}

答案 1

从技术上讲,它是 ,而不是零,如果你承认支持数组的延迟初始化。看: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;

您所指的只是在所有初始空对象之间共享的零大小的初始数组对象。也就是说,懒惰保证了容量,Java 7中也存在这种优化。ArrayList10

诚然,构造函数合同并不完全准确。也许这就是这里混乱的根源。

背景

这是迈克·杜古(Mike Duigou)的一封电子邮件

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

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

此修订后的实现不会向任何一个类引入任何新字段。对于 ArrayList,仅当以默认大小创建列表时,才会对后备数组进行惰性分配。根据我们的性能分析团队,大约 85% 的 ArrayList 实例是以默认大小创建的,因此此优化对绝大多数情况都有效。

对于 HashMap,我们会创造性地使用阈值字段来跟踪请求的初始大小,直到需要存储桶数组。在读取端,使用 isEmpty() 测试空映射案例。在写入大小上,使用比较 (table == EMPTY_TABLE) 来检测是否需要膨胀存储桶数组。在 readObject 中,需要做更多的工作来尝试选择有效的初始容量。

寄件人: http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html


答案 2

在java 8中,ArrayList的默认容量为0,直到我们将至少一个对象添加到ArrayList对象中(您可以称之为惰性初始化)。

现在的问题是,为什么在JAVA 8中进行了这种更改?

答案是节省内存消耗。数以百万计的数组列表对象是在实时java应用程序中创建的。10 个对象的默认大小意味着我们在创建时为基础数组分配 10 个指针(40 或 80 个字节),并用 null 填充它们。空数组(填充空值)占用大量内存。

惰性初始化将此内存消耗推迟到您将实际使用数组列表的那一刻。

请参阅以下代码以获取帮助。

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 的默认容量对此进行了详细解释。


推荐