打字猴:1.700443394e+09
1700443394
1700443395 throw new IllegalArgumentException(“Illegal Capacity:”+initialCapacity);
1700443396
1700443397 //声明指定长度的数组,容纳element
1700443398
1700443399 this.elementData=new Object[initialCapacity];
1700443400
1700443401 }
1700443402
1700443403 默认初始化时声明了一个长度为10的数组,在通过add方法增加第11个元素时,ArrayList类就自动扩展了,新的elementData数组长度是(10×3)/2+1,也就是16,当增加到第17个元素时再次扩容为(16×3)/2+1,也就是25,依此类推,实现了ArrayList的动态数组管理。
1700443404
1700443405 从这里我们可以看出,如果不设置初始容量,系统就按照1.5倍的规则扩容,每次扩容都是一次数组的拷贝,如果数据量很大,这样的拷贝会非常耗费资源,而且效率非常低下。如果我们已经知道一个ArrayList的可能长度,然后对ArrayList设置一个初始容量则可以显著提高系统性能。比如一个班级的学生,通常也就是50人左右,我们就声明ArrayList的默认容量为50的1.5倍(元素数量小,直接计算,避免数组拷贝),即new ArrayList<Studeng>(75),这样在使用add方法增加元素时,只要在75以内都不用做数组拷贝,超过了75才会按照默认规则扩容(也就是1.5倍扩容)。如此处理,对我们的开发逻辑并不会有任何影响,而且还可以提高运行效率(在大数据量下,是否指定容量会使性能相差5倍以上)。
1700443406
1700443407 弄明白了ArrayList的长度处理方式,那其他集合类型呢?我们先来看Vector,它的处理方式与ArrayList相似,只是数组的长度计算方式不同而已,代码如下:
1700443408
1700443409 private void ensureCapacityHelper(int minCapacity){
1700443410
1700443411 int oldCapacity=elementData.length;
1700443412
1700443413 if(minCapacity>oldCapacity){
1700443414
1700443415 Object[]oldData=elementData;
1700443416
1700443417 //若有递增步长,则按照步长增长;否则,扩容2倍
1700443418
1700443419 int newCapacity=(capacityIncrement>0)?(oldCapacity+capacityIncrement)
1700443420
1700443421 :(oldCapacity*2);
1700443422
1700443423 //越界检查,否则超过int最大值
1700443424
1700443425 if(newCapacity<minCapacity){
1700443426
1700443427 newCapacity=minCapacity;
1700443428
1700443429 }
1700443430
1700443431 elementData=Arrays.copyOf(elementData, newCapacity);
1700443432
1700443433 }
1700443434
1700443435 }
1700443436
1700443437 Vector与ArrayList不同的地方是它提供了递增步长(capacityIncrement变量),其值代表的是每次数组拓长时要增加的长度,不设置此值则是容量翻倍(默认是不设置递增步长的,可以通过构造函数来设置递增步长)。其他集合类的扩容方式与此相似,如HashMap是按照倍数增加的,Stack继承自Vector,所采用的也是与其相同的扩容原则等,读者有兴趣可以自行研读一下JDK的源码。
1700443438
1700443439 注意 非常有必要在集合初始化时声明容量。
1700443440
1700443441
1700443442
1700443443
[ 上一页 ]  [ :1.700443394e+09 ]  [ 下一页 ]