kev*_*rpe 88 java arraylist java-8
我记得,在Java 8之前,默认容量ArrayList
是10.
令人惊讶的是,对default(void)构造函数的注释仍然说: Constructs an empty list with an initial capacity of ten.
来自ArrayList.java
:
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
...
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
Run Code Online (Sandbox Code Playgroud)
Luk*_*der 105
从技术上讲,10
如果您承认后备阵列的延迟初始化,则不是零.看到:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
Run Code Online (Sandbox Code Playgroud)
哪里
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
Run Code Online (Sandbox Code Playgroud)
你所指的只是在所有最初空的ArrayList
对象之间共享的零大小的初始数组对象.即容量10
是保证懒惰地,其存在也Java 7中的最优化.
不可否认,构造函数合同并不完全准确.也许这就是混乱的根源.
这是Mike Duigou的电子邮件
我发布了空ArrayList和HashMap补丁的更新版本.
http://cr.openjdk.java.net/~mduigou/JDK-7143928/1/webrev/
此修订的实现不会为任何一个类引入新字段.对于ArrayList,仅当列表以默认大小创建时,才会发生后备阵列的延迟分配.根据我们的性能分析团队,大约85%的ArrayList实例是以默认大小创建的,因此这种优化对于绝大多数情况都是有效的.
对于HashMap,创建使用阈值字段来跟踪请求的初始大小,直到需要存储桶阵列.在读取端,使用isEmpty()测试空映射大小写.在写入大小上,(table == EMPTY_TABLE)的比较用于检测是否需要给桶阵列充气.在readObject中,尝试选择有效的初始容量还有一些工作要做.
来自:http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html
Sha*_*ngh 18
在java 8中,ArrayList的默认容量为0,直到我们将至少一个对象添加到ArrayList对象中(您可以将其称为延迟初始化).请参阅以下代码以获取帮助.
ArrayList al = new ArrayList(); //Size: 0, Capacity: 0
ArrayList al = new ArrayList(5); //Size: 0, Capacity: 5
ArrayList al = new ArrayList(new ArrayList(5)); //Size: 0, Capacity: 0
al.add( "shailesh" ); //Size: 1, Capacity: 10
public static void main( String[] args )
throws Exception
{
ArrayList al = new ArrayList();
getCapacity( al );
al.add( "shailesh" );
getCapacity( al );
}
static void getCapacity( ArrayList<?> l )
throws Exception
{
Field dataField = ArrayList.class.getDeclaredField( "elementData" );
dataField.setAccessible( true );
System.out.format( "Size: %2d, Capacity: %2d%n", l.size(), ( (Object[]) dataField.get( l ) ).length );
}
Response: -
Size: 0, Capacity: 0
Size: 1, Capacity: 10
Run Code Online (Sandbox Code Playgroud)
现在问题是为什么在JAVA 8中完成了这个改变?
答案是节省内存消耗.在实时Java应用程序中创建了数百万个数组列表对象.默认大小为10个对象意味着我们在创建时为底层数组分配10个指针(40或80个字节),并用空值填充它们.空数组(填充空值)占用大量内存.
延迟初始化会推迟此内存消耗,直到您实际使用数组列表为止.
文章Java 8中ArrayList的默认容量详细解释了它.
如果使用ArrayList完成的第一个操作是传递addAll
一个包含十个以上元素的集合,那么创建一个初始十元素数组以保存ArrayList内容的任何工作都将被抛出窗口.每当有东西被添加到ArrayList时,都需要测试结果列表的大小是否超过后备存储的大小; 允许初始后备存储的大小为零而不是10将导致此测试在列表的生命周期中失去一个额外的时间,该列表的第一个操作是"添加",这将需要创建初始的十项数组,但该成本是低于创建一个永远不会被使用的十项数组的成本.
话虽如此,如果有一个"addAll"超载指定在当前列表之后可能会将多少项(如果有的话)添加到列表中,那么在某些情况下可能会进一步提高性能.用它来影响它的分配行为.在某些情况下,将最后几个项添加到列表中的代码将非常清楚该列表永远不需要除此之外的任何空间.在许多情况下,列表将填充一次,之后从未修改过.如果在点代码知道列表的最终大小将是170个元素,它有150个元素和大小为160的后备存储,将后备存储增长到320大小将是无益的,并将其保留为320或修改为170的效率低于简单地将下一个分配增加到170.
归档时间: |
|
查看次数: |
59775 次 |
最近记录: |