我有一个关于Java ArrayList
的基本问题。
使用默认构造函数声明和初始化ArrayList
时,会创建10个元素的内存空间。现在,当我添加第11个元素时,会发生什么?是否会创建具有20(或更多)元素容量的新内存空间(这需要将元素从第一个内存位置复制到新位置)或其他什么东西?
我查了here。但我没有找到答案。
请分享知识。 感谢。
答案 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.5
和int 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)。
编辑:
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 JDK6
和15 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,因此newCapacity
是10 + 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)
Arraylist 默认容量为 10。
[1,2,3,4,5.....10]
如果你想在java中增加Arraylist的大小,你可以应用这个
公式-
int newcapacity,当前容量;
新增容量 =((当前容量*3/2)+1)
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)添加时间。
答案 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会增加加载因子的大小:
上下文: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中。