ArrayList:大小如何增加?
我有一个关于Java ArrayList
的基本问题。
当使用默认构造函数声明和初始化ArrayList
,会创build10个元素的内存空间。 现在,当我添加第11个元素时,会发生什么? 将新的内存空间创build与20(或更多)的元素容量(这需要复制元素从第一个内存位置到新的位置)还是别的什么?
我在这里检查。 但是我没有find答案。
请分享知识。 谢谢。
一个新的数组被创build,旧的内容被复制。 这就是API级别的所有知识。 从文档引用(我强调):
每个
ArrayList
实例都有一个容量。 容量是用于存储列表中的元素的数组的大小。 它总是至less与列表大小一样大。 当元素被添加到ArrayList时,其容量会自动增长。 增长政策的细节并未超出添加元素具有不变摊销时间成本的事实。
就ArrayList
的具体实现(比如Sun的实现)而言,在他们的情况下,您可以在源代码中看到血淋淋的细节。 但是,当然,依靠具体实施的细节通常不是一个好主意。
它将取决于实现,但是来自Sun Java 6的源代码:
int newCapacity = (oldCapacity * 3)/2 + 1;
这是在ensureCapacity
方法。 其他JDK实现可能会有所不同。
Sun的JDK6:
我相信它会增长到15个元素。 不是编码出来,而是看着jdk中的grow()代码。
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.5
和int newCapacity = oldCapacity + (oldCapacity >> 1);
>>
是右移运算符,它将数字减半。 从而,
int newCapacity = oldCapacity + (oldCapacity >> 1);
=> int newCapacity = oldCapacity + 0.5*oldCapacity;
=> int newCapacity = 1.5*oldCapacity ;
当我们尝试添加一个对象到数组列表时,
Java会检查以确保现有arrays中有足够的容量来容纳新对象。 如果不是, 则创build一个更大尺寸的 新数组,使用Arrays.copyOf将旧数组复制到新数组 ,并将新数组分配给现有数组。
看下面的代码(从GrepCode.com上的Java ArrayList代码中获取)。
编辑:
public ArrayList()构造一个初始容量为10的空列表。
public ArrayList(int initialCapacity)我们可以指定初始容量。
public ArrayList(Collection c)按照集合迭代器返回的顺序,构造一个包含指定集合元素的列表。
现在,当我们使用ArrayList()构造时,我们得到一个大小为10的ArrayList。在列表中添加第11个元素,在ensureCapacity()方法内创build新的Arraylist。
使用以下公式:
int newCapacity= (oldCapacity * 3)/2 +1;
当使用默认构造函数声明和初始化ArrayList时,将创build10个元素的内存空间。 现在,当我添加第11个元素时,会发生什么
ArrayList创build一个具有以下大小的新对象
即OldCapacity * 3/2 + 1 = 10 * 3/2 + 1 = 16
通常情况下,ArrayListtypes容器的内存会增加一倍。 因此,如果您最初有10个项目的空间,并且您添加了10个,则第11个项目将被添加到包含20个项目的新(内部)数组中。 这样做的原因是,如果当数组已经以固定大小增量递增时,增加项目的增量成本从O(n ^ 2)减less到每当内部数组已满时加倍大小为好的O(n)。
上下文java 8
我在Oracle java 8实现的上下文中给出了我的答案,因为在阅读了所有的答案之后,我发现在java 6的上下文中,gmgmiller给出了一个答案,并且在java 7的上下文中给出了另一个答案。但是,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一样。
会发生什么是一个新的arrays是用n * 2空格创build的,然后复制旧arrays中的所有项目,并将新项目插入到第一个空闲空间中。 总而言之,这会导致ArrayList的O(N)添加时间。
如果您使用的是Eclipse,请安装Jad和Jadclipse以反编译库中保存的JAR。 我这样做是为了读取原始的源代码。
上下文:JDK 7
在向ArrayList
添加一个元素的同时,以下public ensureCapacityInternal
调用和其他私有方法调用在内部发生以增加大小。 这是dynamic增加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); }
当使用默认构造函数声明和初始化ArrayList时,将创build10个元素的内存空间。
没有。 当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;
PS没有足够的声誉来评论问题,所以我把这个作为答案,因为没有人指出这个错误的假设。
ArrayList
大小总是随着n+n/2+1
增加。
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
数组列表的默认大小是10.当我们添加第11个….数组列表增加大小(n * 2)。 存储在旧数组列表中的值被复制到大小为20的新数组列表中。