显式设置 ArrayList 的容量有什么好处

What is the benefit of setting the capacity of an ArrayList explicitly

在javaArrayList中我们有一个构造函数-

ArrayList(int capacity)

和两个方法 -

void ensureCapacity(int minCapacity)

void trimToSize()

考虑一个代码示例:

ArrayList<String> arrayList3 = new ArrayList<>(5);
System.out.println(arrayList3.size());

arrayList3.add("Zebra");
arrayList3.add("Giraffe");
arrayList3.add("Bison");

System.out.println(arrayList3);
System.out.println(arrayList3.size());

arrayList3.add("Rhino");
arrayList3.add("Hippo");
arrayList3.add("Elephant");
arrayList3.add("Antelope");

System.out.println(arrayList3);
System.out.println(arrayList3.size());

输出:

0
[Zebra, Giraffe, Bison]
3
[Zebra, Giraffe, Bison, Rhino, Hippo, Elephant, Antelope]
7

在这里,我看不出设置初始容量如何影响程序的执行。 ArrayList 是一个灵活的列表,可以根据需要更改大小。那么显式设置容量有什么意义呢?

如果我想明确设置容量,有没有什么方法可以查看当前容量?由于int size()显然不适用于此处。

ArrayList 作为 Dynamic array 数据结构的实现。

它会在其底层数组变满时调整大小(即当前列表索引超过底层数组的最后一个有效索引)。

发生这种情况时,方法 add()(或 addAll)将在内部调用方法 grow()。这将使容量翻倍。 IE。它将创建一个 新数组,其中 length 比之前的 length 大两倍,外加一些 新元素 不适合当前尺寸。

增长的成本为O(n),因为所有先前添加的元素都需要复制到新数组

提示:当不需要调整大小时,将在恒定时间内添加一个新元素 O(1).

No-argument constructor 创建容量为 10.

ArrayList

如果您希望新创建的 ArrayList 最终包含比方说 50,000 元素,那么使用 重载构造函数 来提供50,000 的初始容量,以便通过避免不必要的调整大小来提高性能。

此外,为此你可以使用 ensureCapacity() 方法,它可以在 ArrayList class 中访问(而不是在 List 接口中,因为 capacity 不适用于没有数组支持的 LinkedList

is there any method to view the current capacity

不,没有。这就是所谓的encapsulationArrayListStringBuilderHashMap 等由普通数组支持,但它们不允许直接与其底层数组进行交互。

但是如果你遇到数组最初增加大小然后大量元素被删除的情况,并且你想释放未占用的堆space,你可以使用方法trimToSize():

Trims the capacity of this ArrayList instance to be the list's current size. An application can use this operation to minimize the storage of an ArrayList instance.

但要谨慎使用,因为它会导致循环增长和修剪,从而导致性能下降。

注意如果列表大小适中,不用担心未占用的数量space,或者,如果您不希望一次性删除 80% 的数据。 IE。即使列表很大,但它的 50% 个元素被删除,并且你在它上面应用 trimToSize(),它会用下一个添加的元素恢复它以前的容量——这就是不断增长和收缩的场景表现不佳的列表。

作为一个可能的选项,如果您遇到 大部分数据 可以从列表中删除的情况,而不是使用 trimToSize(),您可以过滤掉必须保留的元素,将它们放入新列表并取消引用前一个。