概括

因为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;
    }
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐