Java 当我们删除元素时,ArrayList的容量会减少吗?

Java 当我们删除元素时,ArrayList的容量会减少吗?,java,collections,arraylist,Java,Collections,Arraylist,ArrayList的默认容量为10个对象。当大小超过10个对象时,ArrayList将在内部增加其容量。从ArrayList中删除对象时,容量是否会减少 如果ArrayList容量没有减少,是否会导致性能问题?它不会自动减少容量。从医生那里 public void trimToSize() 将此ArrayList实例的容量修剪为列表的当前大小。应用程序可以使用此操作最小化ArrayList实例的存储 在arraylist中有几种删除方法,我将使用按索引删除版本作为示例 public

ArrayList的默认容量为10个对象。当大小超过10个对象时,ArrayList将在内部增加其容量。从ArrayList中删除对象时,容量是否会减少


如果ArrayList容量没有减少,是否会导致性能问题?

它不会自动减少容量。从医生那里

    public void trimToSize() 

将此ArrayList实例的容量修剪为列表的当前大小。应用程序可以使用此操作最小化ArrayList实例的存储

在arraylist中有几种删除方法,我将使用按索引删除版本作为示例

 public E remove(int index) {

     rangeCheck(index);
     modCount++;
     E oldValue = elementData(index);

     int numMoved = size - index - 1;

     if (numMoved > 0)
           System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);

     elementData[--size] = null; // Let gc do its work


     return oldValue;

 }
需要注意的最重要的一点是,从未在
elementData
中创建新数组,因此其大小不会更改,只复制元素


如果需要减少数组列表的容量(通常不会使用),请使用
trimToSize()

ArrayList提供了一个方法trimToSize(),该方法 “将此ArrayList实例的容量修剪为列表的当前大小。应用程序可以使用此操作最小化ArrayList实例的存储。”请参阅


如果任何其他方法以静默方式执行此操作,这将取决于JRE提供的实现。

当我们从ArrayList中删除对象时,容量是否会降低。

答案是否定的。如果你观察这个类的源代码,你就会得到答案。

没有任何操作可以减少ArrayList的
remove()
方法的容量。

据我所知,ArrayList的容量只是增加了,要减少它必须将一个数组复制到另一个数组

我试着用我自己的实验来回答你们的问题。您无法查找数组列表的当前容量,因此我正在运行垃圾收集器并检查可用内存

My results are:
             Before:  125637904
         After Aloc:  126959888 -1321984
       After Insert:  126718560 241328
        After Clear:  126958496 -239936
         After trim:  126998432 -39936
      After nullify:  126998400 32
这很奇怪,我无法解释。分配列表会减少可用内存。在列表中插入增加的可用内存(我没想到)清除列表减少的可用内存(???)再次修剪列表减少可用内存(似乎没有清除),并将列表指针设置为null应该可以让我们回到开始的位置,但事实并非如此

我的代码如下:

package metcarob.com.dev.rubbish;

import java.util.ArrayList;
import java.util.List;

public class ArrayListTest {

    private static long outputMem(String pre, long last) {
        Runtime.getRuntime().gc();
        String pre2 = "                    " + pre;
        System.out.print(pre2.substring(pre2.length()-20) + "  ");

        long tv = Runtime.getRuntime().freeMemory();

        System.out.print(tv);

        if (last!=0) {
            System.out.print(" " + (last - tv));
        }

        System.out.println("");

        return tv;
    }

    public static void main(String[] args) {

        long lm = outputMem("Before:",0);

        ArrayList<String> lis = new ArrayList<String>();
        lis.ensureCapacity(10000);

        lm = outputMem("After Aloc:", lm);

        for (int c=0;c<10000;c++) {
            lis.add(new String("ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"));
        };

        lm = outputMem("After Insert:", lm);

        lis.clear();

        lm = outputMem("After Clear:", lm);

        lis.trimToSize();

        lm = outputMem("After trim:", lm);

        lis = null;

        lm = outputMem("After nullify:", lm);

    }

}
package metcarob.com.dev.垃圾;
导入java.util.ArrayList;
导入java.util.List;
公共类ArrayListTest{
私有静态long outputMem(字符串前置、长尾){
Runtime.getRuntime().gc();
字符串pre2=“”+pre;
System.out.print(pre2.substring(pre2.length()-20)+”);
long tv=Runtime.getRuntime().freemory();
系统输出打印(电视);
如果(最后一个!=0){
System.out.print(“+(last-tv));
}
System.out.println(“”);
返回电视;
}
公共静态void main(字符串[]args){
长lm=输出mem(“之前:”,0);
ArrayList lis=新的ArrayList();
资产负债表(10000);
lm=输出mem(“在Aloc之后:,lm);

对于(int c=0;c您询问了性能影响。您必须澄清“降低”性能的含义。如果每次降低阵列时都必须调整阵列大小,则每次都会重新复制阵列。另一方面,如果容量保持不变,则会占用不必要的内存

这是您的用例决定了这将如何影响用户感知的性能。它们是否运行在内存不足的机器上?我们是否在谈论大型的、主要是静态的阵列?阵列是否一直在变化

Java实现仅在需要时更改底层数组。这有助于避免不必要的拷贝,而以牺牲内存大小为代价。但是,它们使您能够在必要时对其进行修剪

移除元素时,
ArrayList
的容量是否会减少

否。这是一个实现细节,但是
ArrayList
类的任何(标准)实现都没有在删除元素时自动减少列表的容量

如果
ArrayList
容量没有减少,是否会导致性能问题

嗯,总的来说没有

首先,列表通常不会收缩。(大多数列表的生命周期相对较短。它们经过处理,通过追加构建,然后进行处理。移除列表元素相对不常见……尽管这取决于应用程序。)因此,大多数情况下,这个问题都是没有意义的

其次,除非
ArrayList
的大小过大,否则列表末尾未使用的空间不会对性能产生显著影响。事实上,只有当垃圾收集器标记并复制列表时,才会直接影响任何内容。而且影响相对较小,因为区域beyond
ArrayList
的逻辑端始终清除为
null
,以防止内存泄漏

值得注意的是,通过追加到初始空列表而创建的
ArrayList
可能会有一个平均过大50%的备份数组。这是因为
ArrayList
s扩展备份数组的内置策略是将其大小加倍。这使得
append
成为一个摊销
O(1)
操作

第三,
delete
或类似操作无法“知道”列表接下来会发生什么,因此无法判断调整大小是否合适

如果您的应用程序确实需要,它可以在删除元素后调用
trimToSize()
。但是,请注意:

  • 调用
    trimToSize()
    代价很高。
    ArrayList
    实现将创建一个全新的备份数组(大小正好合适)并复制所有数组元素

  • 下次将元素插入或附加到