Java ArrayList中的初始容量

Java ArrayList中的初始容量,java,arraylist,collections,Java,Arraylist,Collections,我需要创建一个ArrayList,我预先知道这个数组的最大大小不会超过5个元素 我想从社区了解initailCapacity将大小指定为5是否有任何性能优势 List<String> list = new ArrayList<>(5); 或 哪个更好?来自ArrayList.java /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; 不提供容量时使用

我需要创建一个ArrayList,我预先知道这个数组的最大大小不会超过5个元素

我想从社区了解initailCapacity将大小指定为5是否有任何性能优势

List<String> list = new ArrayList<>(5);

哪个更好?

来自ArrayList.java

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;
不提供容量时使用的默认容量为10。因此,将大小指定为5将意味着使用更少的内存


如果您知道您将只拥有一个特定的数字,那么数组可能是一个更轻量级的选择。

是的,它将提高性能,因为默认值为10的内存不会占用太多。

如果您确实希望列表通常至少填充一些元素,但不超过5个,那么是的,将初始容量设置为5可能是最有效的方法

后备数组的延迟实例化 但是,如果最常见/预期的情况是,甚至没有一个项目被添加到列表中,那么没有任何指定初始容量的构造函数可能更有效。这是因为假设使用了较新的JDK版本,ArrayList根本不会分配任何支持数组,而只是使用在所有空的、默认构造的ArrayList之间共享的引用。只有当您开始向它添加项目时,它才会实际分配内存

将第一个元素添加到ArrayList时,将创建一个新的备份数组。新数组的默认大小为10

要了解最初使用的是对支持数组的共享引用,您可以查看OpenJDK的github,例如,您可以找到no-args构造函数的实现。情况如下:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
 * 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 = {};
备份数组elementData分配到的引用在文件中声明得更高,如下所示:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
 * 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 = {};

这不仅发生在OpenJDK中,也发生在Oracle的JDK中。至少,我电脑上的版本是这样的。我不知道是否有容易找到的Oracle源代码链接,但是OpenJDK源代码更容易在网上找到。

是的,它会提高性能,但只会提高一点点

如果你知道列表总是那么长,那么最好将列表设置为一个特定的长度,但是这样的使用很少,所以不应该是一个常见的问题


此外,如果它是一个由5个成员组成的列表,那么您最好只创建一个包含5个字段的新对象。这将使处理这些数据更容易、更快,因为不需要搜索列表。

这取决于用例。假设您已经知道一定要存储特定数量的对象(在本例中为字符串对象),那么如果您在创建ArrayList时指定其大小,将在该步骤分配内存

List<String> list = new ArrayList<>(5);

然后,一旦元素被填充,ArrayList的大小将随着您添加更多对象而动态扩展。假设您确实要向ArrayList添加50个元素,那么将初始容量指定为50,这将导致分配那么多空间。这将是一种更有效的方法,因为在初始化之后,您不会动态分配多达50个元素的内存。在ArrayList展开时分配内存将影响性能。同时,如果您指定了较大的初始大小,则会浪费宝贵的内存空间。

这里有几篇关于这一点的文章,以及Java文档中的信息。所以我只想说一句:是的,这很可能有性能优势。Java必须用一定的大小初始化ArrayList;如果它选择低于5的值,它将不得不在以后重新分配,从而浪费CPU周期。如果它选择了更大的内容,可能会浪费内存。不要忘记/低估LinkedList,你的意思是@JoopEggen,因为一个有五个条目的LinkedList已经比默认容量为十个的ArrayList消耗了多得多的内存?@Holger我的意思是LinkedList可能很少被考虑。5可能是一般最大值,可能是80%,最多为1,或诸如此类。那么链表可能更合适——我想。@JoopEggen经常被忽略的是,可以选择使用专门化的不可变列表,即Collections.emptyList、Collections.singletonList…,或Java 9的list.of…,它目前专门化了零、一和两个元素。如中所述,具有默认初始容量的ArrayList(从未添加到)不会有支持数组,因此LinkedList只有在只有一个元素但需要可变时才会发光。看看JDK8中的无参数ArrayList构造函数,它的默认容量不是10,实际上是0。同意,但只要添加了任何项,尺寸将增加到10;请查看ensureCapacityInternalYes,除非您试图将集合添加到ArrayList中,在这种情况下,它将使用10与传入集合大小之间的较大值。无论哪种方式,它都会迫使基础设施的扩张
在指定显式初始容量时未完成的数组,因此性能较低。也就是说,对于绝大多数应用程序来说,这种差异可能可以忽略不计。@JonK在使用默认构造函数时,不会创建数组,因此第一次“扩展”与在给定显式容量的情况下在构造函数中创建数组没有什么不同。因此,没有性能差异,除非10的容量不足,并且您的第一个操作不是addAll。ArrayList的初始容量在未明确指定时为零,而不是10。10是当您尝试向其中添加第一个元素时,它将扩展的默认值。Oracle JDK是从与OpenJDK相同的源代码构建的,因此您找到的代码适用于两者。