【面试:基础篇06:ArrayList扩容机制】
01.几种初始化容量情况:
01.无参构造
无参构造默认容量大小为0
02.有参构造
指定大小
根据传入集合的大小
02.使用add方法时容量的变化:
// add方法扩容
List<Integer> L=new ArrayList<Integer>();
Class<? extends List> strClass = L.getClass();
Field field = strClass.getDeclaredField("elementData");// 私有属性elementData存放的是容量的大小
field.setAccessible(true);// 这句的作用是忽略访问控制符
int len = 0;
System.out.println("当有0个元素时"+"这个ArrayList的容量为:"+len);
for (int i=0;i<100;i++) {
L.add(i);
Object[] elementData = (Object[]) field.get(L);
if (elementData.length!=len){
System.out.println("当有"+(i+1)+"到"+elementData.length+"个元素时"+"这个ArrayList的容量为:"+elementData.length);
len=elementData.length;
}
}
结果
当有0个元素时这个ArrayList的容量为:0
当有1到10个元素时这个ArrayList的容量为:10
当有11到15个元素时这个ArrayList的容量为:15
当有16到22个元素时这个ArrayList的容量为:22
当有23到33个元素时这个ArrayList的容量为:33
当有34到49个元素时这个ArrayList的容量为:49
当有50到73个元素时这个ArrayList的容量为:73
当有74到109个元素时这个ArrayList的容量为:109
可以看出初始化容量为0,第一次扩容是10,之后每次扩容都是其容量的1.5倍(准确是 当前容量>>>1 + 当前容量)
03.使用addAll方法时容量的变化:
情况一:
// addAll扩容 情况一:
List<Integer> L=new ArrayList<>();
L.addAll(Arrays.asList(1,2,3,4,5));
Class<? extends List> strClass = L.getClass();
Field field = strClass.getDeclaredField("elementData");// 私有属性elementData存放的是容量的大小
field.setAccessible(true);// 这句的作用是忽略访问控制符
Object[] elementData = (Object[]) field.get(L);
System.out.println("这个ArrayList的容量为:"+elementData.length);
结果
这个ArrayList的容量为:10
可以看出如果初始化容量为0时 添加的元素少于10 则扩容还是为10
情况二:
// addAll扩容 情况二:
List<Integer> L=new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
L.addAll(Arrays.asList(11,12,13,14,15,16));
Class<? extends List> strClass = L.getClass();
Field field = strClass.getDeclaredField("elementData");// 私有属性elementData存放的是容量的大小
field.setAccessible(true);// 这句的作用是忽略访问控制符
Object[] elementData = (Object[]) field.get(L);
System.out.println("这个ArrayList的容量为:"+elementData.length);
结果
这个ArrayList的容量为:16
这时容量大小为16,而不是正常以为15或者22,因为==addAll有特殊的扩容规则==:扩容的大小 是 初始化的容量大小的1.5倍的大小 与 增加后所有元素的容量的大小 的 较大值,这里 初始化容量是10 扩容后是15,而增加后的元素是16 所有这里容量大小为16