ArrayList扩容规则源码解析
概括因为ArrayList用的比较多,然后平时也是只知道ArrayList是基于数组实现的,但是具体也没是怎么实现的,内部的数组是怎么扩容的,这些都没细看,然后最近复习有点无聊,然后看了下代码,跟了下ArrayList的源码,发现里面的扩容规则,其实还挺简单的基本流程扩容基本流程创建ArrayListArrayList有三个构造方法,分别是 无参构造、集合为参数的构造、整型为参数的构造。内部代码分
概括
因为ArrayList用的比较多,然后平时也是只知道ArrayList是基于数组实现的,但是具体也没是怎么实现的,内部的数组是怎么扩容的,这些都没细看,然后最近复习有点无聊,然后看了下代码,跟了下ArrayList的源码,发现里面的扩容规则,其实还挺简单的
基本流程

扩容基本流程
创建ArrayList
ArrayList有三个构造方法,分别是 无参构造、集合为参数的构造、整型为参数的构造。内部代码分别如下无参构造
很简单,直接给一个默认为空的 Object[] 数组即可
为什么用Object[]存储就不多说了吧,可以存所有对象,然后用泛型来管理存储的都是同一个对象。

集合为参数的构造
内部的逻辑就是,直接将集合转为Object数组,然后获取长度,然后复制一个相同的数组即可,那此时,ArrayList内部数组的容量很明显就是当前传入集合的长度了
整型为参数的构造
这个都没什么好做的了,创建一个和传入参数长度一直的数组即可
添加元素
添加元素主要有 add方法以及 addAll方法,使用不同的方法去添加元素的话,扩容的长度当然也是不一样的add


所以人们经常所说的,ArrayList扩容是默认扩容1.5倍,其实是不太准确的,默认扩容长度应该是 newLength = oldLength + (oldLength >> 1)
当然这只是基于add方法的扩容,如果是基于allAll的扩容的话,就不是这样了
addAll


可以看newLength的方法,
1、如当前list长度为10,然后添加一个长度为3的集合,按照算法的话, newLength = oldLength + (oldLength >> 1) 那其实应该是15,然后又传入的minCapacity为13,则此时会Math.max选择大的,所以扩容后的数组长度为15
2、如当前list长度为10,然后添加一个长度为7的集合,按照算法的话, newLength = oldLength + (oldLength >> 1) 那其实应该是15,然后又传入的minCapacity为17,则此时会Math.max选择大的,所以扩容后的数组长度为17
所以要清楚,扩容不是一定每次都是“1.5”倍
查看扩容量的示例
随便粗略的写了一下扩容的示例,最主要就是使用反射获取到ArrayList中的elementData.length,此时就可以获取到内部数组中的长度了,也就知道扩容到多少了。注:java9以上,反射也不能直接访问私有成员,也是会被警告,此时的话只要在启动的时候加上参数 --add-opens java.base/java.util=ALL-UNNAMED 即可
@Test
public void testArrayList() {
ArrayList<Integer> ints = new ArrayList<Integer>();
ints.add(3);
ints.add(3);
ArrayList<Integer> ints2 = new ArrayList<Integer>();
ints.addAll(ints);
ints2.addAll(ints);
System.out.println(length(ints2));
System.out.println(ints2);
System.out.println(length(ints2));
ints2.addAll(ints);
System.out.println(ints2);
System.out.println(length(ints2));
ints2.add(4);
ints2.add(4);
System.out.println(ints2);
System.out.println(length(ints2));
System.out.println(ints);
ints2.addAll(ints);
System.out.println(length(ints2));
}
private int length(ArrayList list) {
Class<ArrayList> arrayListClass = ArrayList.class;
try {
Field elementData = arrayListClass.getDeclaredField("elementData");
elementData.setAccessible(true);
Object[] o = (Object[]) elementData.get(list);
return o.length;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
更多推荐



所有评论(0)