ArrayList:大小如何增加?

时间:2010-12-15 13:53:59

标签: java arrays arraylist collections

我有一个关于Java ArrayList的基本问题。

使用默认构造函数声明和初始化ArrayList时,会创建10个元素的内存空间。现在,当我添加第11个元素时,会发生什么?是否会创建具有20(或更多)元素容量的新内存空间(这需要将元素从第一个内存位置复制到新位置)或其他什么东西?

我查了here。但我没有找到答案。

请分享知识。 感谢。

22 个答案:

答案 0 :(得分:46)

创建一个新数组,并复制旧数组的内容。这就是你在API级别所知道的。引自the docs(我的重点):

  

每个ArrayList实例都有容量。容量是用于存储列表中元素的数组的大小。它始终至少与列表大小一样大。当元素添加到ArrayList时,其容量会自动增加。 除了添加元素具有不变的摊余时间成本这一事实外,未指定增长政策的详细信息。

ArrayList的特定实现(例如Sun)实际发生的情况而言,在他们的情况下,您可以在源代码中看到血腥细节。但是,当然,依靠特定实现的细节通常不是一个好主意......

答案 1 :(得分:34)

Sun的JDK6:

我相信它会增长到15个元素。不编码,但看着grow() jdk中的代码。

int newCapacity then = 10 +(10>> 1)= 15.

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

来自Javadoc,它说这是来自Java 2,所以它在Sun JDK中是一个安全的赌注。

编辑:对于那些没有得到倍增系数1.5int newCapacity = oldCapacity + (oldCapacity >> 1);

之间关系的人

>>是右移运算符,它将数字减少到一半。 因此,int newCapacity = oldCapacity + (oldCapacity >> 1);
=&GT; int newCapacity = oldCapacity + 0.5*oldCapacity;
=&GT; int newCapacity = 1.5*oldCapacity ;

答案 2 :(得分:28)

这取决于实现,但取决于Sun Java 6源代码:

int newCapacity = (oldCapacity * 3)/2 + 1;

这是ensureCapacity方法。其他JDK实现可能会有所不同。

答案 3 :(得分:11)

当我们尝试将对象添加到arraylist时,

Java检查以确保现有阵列中有足够的容量来容纳新对象。如果没有,则创建更大尺寸的新阵列,使用 Arrays.copyOf 和新阵列将旧阵列复制到新阵列被分配给现有数组。

查看下面的代码(取自GrepCode.com上的Java ArrayList Code)。

Check this example

enter image description here

  

编辑:

public ArrayList()构造一个初始容量为10的空列表。

public ArrayList(int initialCapacity)我们可以指定初始容量。

public ArrayList(Collection c)按照集合迭代器返回的顺序构造一个包含指定集合元素的列表。

现在,当我们使用ArrayList()constructore时,我们得到一个 Size = 10 的ArrayList 在列表中添加第11个元素时,会在ensureCapacity()方法中创建新的Arraylist。

使用以下公式:

  int newCapacity= (oldCapacity * 3)/2 +1;

答案 4 :(得分:6)

使用默认声明和初始化ArrayList时 构造函数,将创建10个元素的内存空间。 现在,当我添加第11个元素时,会发生什么

ArrayList创建一个具有以下大小的新对象

即OldCapacity * 3/2 + 1 = 10 * 3/2 + 1 = 16

答案 5 :(得分:4)

通常,ArrayList类型容器的内存通过加倍来增加。因此,如果您最初有10个项目的空间并且您添加了10个项目,则第11个项目将添加到包含20个项目的新(内部)数组中。这样做的原因是,如果在每次内部阵列满时将数组加倍时,如果数组以固定大小增量递增到一个漂亮的O(n),则添加项的增量成本将从O(n ^ 2)减少。

答案 6 :(得分:4)

直到JDK 6,容量随着公式newCapacity = (oldCapacity * 3/2) + 1而增长。

在JDK 7及更高版本中,公式更改为newCapacity = oldCapacity + (oldCapacity >> 1)

因此,如果初始容量为10,则新容量将为16 in JDK615 in above JDK6

答案 7 :(得分:3)

  

Context java 8

我在Oracle java 8实现的上下文中给出了我的答案,因为在阅读了所有答案之后,我发现gmgmiller给出了java 6上下文中的答案,并且在上下文中给出了另一个答案。但是没有给出java 8如何实现大小增加。

在java 8中,大小增加行为与java 6相同,请参阅ArrayList的grow方法:

   private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

关键代码是这一行:

int newCapacity = oldCapacity + (oldCapacity >> 1);

很明显,增长因子也是1.5,与java 6相同。

答案 8 :(得分:2)

  

使用默认构造函数声明和初始化ArrayList时,会创建10个元素的内存空间。

NO。初始化ArrayList时,将为空数组进行内存分配。默认容量(10)的内存分配仅在向ArrayList添加第一个元素时进行。

 /**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
 * DEFAULT_CAPACITY when the first element is added.
 */
private transient Object[] elementData;

P.S。没有足够的声誉来评论问题,所以我把它作为一个答案,因为没有人在早些时候指出这个错误的假设。

答案 9 :(得分:2)

让我们看一下这段代码(jdk1.8)

@Test
    public void testArraySize() throws Exception {
        List<String> list = new ArrayList<>();
        list.add("ds");
        list.add("cx");
        list.add("cx");
        list.add("ww");
        list.add("ds");
        list.add("cx");
        list.add("cx");
        list.add("ww");
        list.add("ds");
        list.add("cx");
        list.add("last");
    }

1)在插入“最后一个”时将断点放在行上

2)转到ArrayList的添加方法 您会看到

ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;

3)转到guaranteeCapacityInternal方法,此方法调用ensureExplicitCapacity

4)

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
            return true;

在我们的示例中,minCapacity等于11 11-10 > 0,因此您需要grow方法

5)

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

让我们描述每个步骤:

1)oldCapacity = 10,因为我们没有在初始化ArrayList时放置此参数,因此它将使用默认容量(10)

2)int newCapacity = oldCapacity + (oldCapacity >> 1); 此处newCapacity等于oldCapacity加上oldCapacity,右移一位 ({oldCapacity is 10是二进制表示形式00001010向右移动一位,我们将得到00000101,它是十进制的5,因此newCapacity10 + 5 = 15

3)

if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;

例如,您的初始容量为1,将第二个元素添加到arrayList newCapacity将等于1(oldCapacity) + 0 (moved to right by one bit) = 1 在这种情况下,newCapacity小于minCapacity,并且elementData(arrayList内的数组对象)无法容纳新元素,因此newCapacity等于minCapacity

4)

if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

检查数组大小是否达到MAX_ARRAY_SIZE(即Integer.MAX-8)Why the maximum array size of ArrayList is Integer.MAX_VALUE - 8?

5)最后,它将旧值复制到长度为15的newArray中。

答案 10 :(得分:1)

  1. Arraylist 默认容量为 10。

  2. [1,2,3,4,5.....10]

  3. 如果你想在java中增加Arraylist的大小,你可以应用这个

  4. 公式-

  5. int newcapacity,当前容量;

  6. 新增容量 =((当前容量*3/2)+1)

  7. arralist 为 [1,2,3,4,5.....10,11],arraylist 容量为 16。

答案 11 :(得分:1)

从JDK源代码中,我发现以下代码

int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);

答案 12 :(得分:0)

如果使用n * 2个空格创建新数组,则会复制旧数组中的所有项目,并将新项目插入第一个空闲空间。总而言之,这会导致ArrayList的O(N)添加时间。

如果您正在使用Eclipse,请安装JadJadclipse以反编译库中保存的JAR。我这样做是为了阅读原始源代码。

答案 13 :(得分:0)

Java 中的 ArrayList 一旦满了就会增长 50% 的原始容量。

答案 14 :(得分:0)

(oldSize * 3)/ 2 + 1

如果您使用默认构造函数,则ArrayList的初始大小将为10,否则您可以在创建ArrayList的对象时传递数组的初始大小。 em>

示例:如果使用默认构造函数

List<String> list = new ArrayList<>();
list.size()

示例:如果使用参数化构造函数

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

答案 15 :(得分:0)

在Jdk 1.6中: 新容量=(当前容量* 3/2)+ 1;

在Jdk 1.7:

int j = i +(i>&gt; 1); 这和 新容量=(当前容量* 1/2)+当前容量;

例如:尺寸将增加如:10 - > 15 - > 22 - > 33

答案 16 :(得分:0)

static int getCapacity(ArrayList<?> list) throws Exception {
            Field dataField = ArrayList.class.getDeclaredField("elementData");
            dataField.setAccessible(true);
            return ((Object[]) dataField.get(list)).length;
    }

使用上述方法检查修改arraylist时的大小。

答案 17 :(得分:0)

ArrayList的默认容量为10。 一旦容量达到其最大容量,ArrayList的大小将为16,一旦容量达到其最大容量16,ArrayList的大小将为25并且基于数据大小继续增加.....

如何?这是答案和公式

New capacity = (Current Capacity * 3/2) + 1

因此,如果默认容量为10,则

Current Capacity = 10
New capacity = (10 * 3/2) + 1
Output is 16

答案 18 :(得分:0)

ArrayList的大小始终会随着n+n/2+1而增加。

答案 19 :(得分:0)

在以下情况下,ArrayList会增加加载因子的大小:

  • 初始容量: 10
  • 加载系数: 1(即列表已满)
  • 增长率: current_size + current_size / 2
  

上下文:JDK 7

ArrayList中添加元素时,会在内部发生以下public ensureCapacityInternal调用和其他私有方法调用以增加大小。这是动态增加ArrayList大小的原因。 在查看代码时,您可以通过命名约定来理解逻辑,因为这个原因我没有添加显式描述

public boolean add(E paramE) {
        ensureCapacityInternal(this.size + 1);
        this.elementData[(this.size++)] = paramE;
        return true;
    }

private void ensureCapacityInternal(int paramInt) {
        if (this.elementData == EMPTY_ELEMENTDATA)
            paramInt = Math.max(10, paramInt);
        ensureExplicitCapacity(paramInt);
    }
private void ensureExplicitCapacity(int paramInt) {
        this.modCount += 1;
        if (paramInt - this.elementData.length <= 0)
            return;
        grow(paramInt);
    }

private void grow(int paramInt) {
    int i = this.elementData.length;
    int j = i + (i >> 1);
    if (j - paramInt < 0)
        j = paramInt;
    if (j - 2147483639 > 0)
        j = hugeCapacity(paramInt);
    this.elementData = Arrays.copyOf(this.elementData, j);
}

答案 20 :(得分:-1)

ArrayList 是集合接口的类。 Java 是开源语言,我们可以改变它的实现。 这里java预定义的实现是: 新容量 = (currentCapacity*3)/2 + 1; 要么 在 JAVASE8 newcapacity = oldCapacity+(oldcapacity>>1);

答案 21 :(得分:-2)

arraylist的默认大小是10.当我们添加第11个时...... arraylist增加了大小(n * 2)。存储在旧arraylist中的值将复制到大小为20的新arraylist中。