在java中,当数组大小很小(不大于5)时,向数组添加项的有效方法是什么

在java中,当数组大小很小(不大于5)时,向数组添加项的有效方法是什么,java,arrays,arraylist,Java,Arrays,Arraylist,向数组中添加项的常用方法是使用ArrayList变量而不是泛型数组并调用add方法 我编写了将项添加到通用数组的方法: public static <T> T[] addItemToArray(T[] objects, T object) { T[] temp = null; temp = Arrays.copyOf(objects, objects.length + 1); temp[objects.length] = object; return

向数组中添加项的常用方法是使用ArrayList变量而不是泛型数组并调用add方法

我编写了将项添加到通用数组的方法:

public static <T> T[] addItemToArray(T[] objects, T object) {
    T[] temp = null;
    temp = Arrays.copyOf(objects, objects.length + 1);
    temp[objects.length] = object;
    return temp;
}
以下哪种方法在速度和内存管理方面更有效?为什么

补充资料


如果需要添加新项,而不仅仅是迭代循环来填充数组,则在运行时使用此方法。同样值得注意的是,数组的大小永远不会超过5。在这种情况下,使用此自定义方法而不是ArrayList会更好吗?

ArrayList.add在某些方面内存效率较低,但比您的实现更快。原因是ArrayList.add不会在每次添加操作中增加基础数组的大小。它有时只会增加大小,而且会增加超过1

具体而言,当阵列空间不足时,阵列大小将使用以下公式增加:

int newCapacity = (oldCapacity * 3)/2 + 1;
这会在阵列已满时将其大小增加约1/2


这意味着在大多数情况下,ArrayList.add只是将一个项放入数组中,只是有时会执行增加数组大小的更昂贵的操作。这样做的缺点是,ArrayList在任何时候分配的空间都略大于所需的空间,这是非常值得的,因为每次操作都会增加数组的大小。ArrayList的工作原理是使用一个固定大小的数组,并按指数放大,也就是说,如果您必须添加一个项目,并且当前的后端阵列已满,则您不会将其复制到大小为+1的阵列,而是复制到大小为*1.5的阵列。这样做是为了最大限度地减少复制操作的数量,而复制操作的成本很高,但可能会浪费内存

ArrayList还有一个很好的方法,名为.ensureCapacityint n,它将数组预先分配到某个最小大小。您可以在长系列的.add操作之前调用此操作,以仅支付一次拷贝成本,而不是在插入过程中多次


换句话说:对于任何显著的插入次数,ArrayList都会比您的实现在时间上表现得更好,在内存上表现得更差。

我将稍微不同意其他一些答案,并说ArrayList.add显然会更高效、更快

ArrayList实际上会创建一个数组,它的大小比它最初需要的要大一点,看起来内存效率要低一点。但它将尽最大努力避免为每个add操作创建许多不必要的数组实例。这比您的实现更快、内存效率更高

在您的实现中,对于每个add,您都将创建一个全新的数组实例。这不是内存效率,并且会为垃圾收集器增加更多的工作

编辑:

下面的示例说明了我所说的ArrayList更高效的内存

比方说,我们尝试使用这两种方法向列表中添加5项

方法1:使用内置ArrayList

我们总共创建了6个数组,总大小为15,不包括与每个创建对象相关的内存开销

因此,正如我们所看到的,使用定制实现开始消耗更多内存并不需要很长时间

这就是为什么在内存和速度方面最好相信内置的ArrayList实现,而不是我们自己的实现


例外情况是,如果您不打算经常调用add,或者您知道需要预先设置数组的大小。但即便如此,您也可以通过向其构造函数传递更具体的initialCapacity来实例化ArrayList,以满足您的具体需求。

当您比较ArrayList.add和您自己的addItemToArray的实现时,你的发现是什么?为什么不做一个基准测试并启发我们呢?你应该能够通过计算两种操作的时间差来自己确定速度问题的答案。当有人试图在没有深入了解主题的情况下实现更好的实现时,这总是很有趣。你所创建的tan是正确的多个实例,但我要说的是,我们的其他两个答案都考虑了任何清理操作结束时的内存使用情况,因此忽略了GCwork@Diego:实际上,即使不考虑GC工作,通过他的实现,他在每次添加操作中创建的所有数组都将使用更多的内存。只需要少量的加法,他就可以轻松地使用比AARYLIST所拥有的更多的内存。当然,但是,如果你只考虑在稳定状态下的内存使用情况,那就更大了。任何暂时状态的配置文件都变得过于依赖于操作序列的配置文件。@迭戈:我不确定是否理解
最后一点。我想说的是,我很现实:我不知道GC何时运行,也不应该依赖于知道。因此,我认为他的实现在任何给定时间都比ArrayList的实现更可能导致更多的内存使用。唯一的例外是,如果他已经预先知道他的数组应该有多大,或者如果他从未调用他的add方法,你是对的。我想说的是,您不应该担心GC,而应该对稳态行为进行评估:即,在所有应该发生的事情都解决之后,给定操作序列结束时的内存使用量是多少?试图估计每一个中间状态,即。GC运行期间/之前包含太多的复杂性,使得估算不合理。那你在哪里停?你还考虑在交换内存/磁盘中加载/存储吗?CPU中断?太多东西:很确定旧的*3/2+1比33%的增长更接近50%。我正在使用这个addItemToArray在需要时在运行时动态添加项目。此外,数组的大小永远不会大于5。在这种情况下,我最好使用我的自定义函数吗?如果你知道数组的大小从来都不大于5,我建议在构造时只分配一个大小为5的数组,并保持不变。数组只包含指向对象的指针,因此数组本身很小。我使用此addItemToArray在需要时在运行时动态添加项。此外,数组的大小永远不会大于5。在这种情况下,使用自定义函数是否更好?
ArrayList<String> list = new ArrayList<>(); // size of internal array: 10.
list.add("a"); // size of internal array: still 10.
list.add("b"); // size of internal array: still 10.
list.add("c"); // size of internal array: still 10.
list.add("d"); // size of internal array: still 10.
list.add("e"); // size of internal array: still 10.
String[] list = new String[0]; // 1 array of size 0.
list = addItemToArray(list, "a"); // 2nd array instance of size 1.
list = addItemToArray(list, "b"); // 3rd array instance of size 2.
list = addItemToArray(list, "c"); // 4th array instance of size 3.
list = addItemToArray(list, "d"); // 5th array instance of size 4.
list = addItemToArray(list, "e"); // 6th array instance of size 5.