ArrayList源码解析

ArrayList是我们在程序日常开发中用到的最常用的类。本文是基于Java8对源码进行分析,java11的源码有些许变化,但是大同小异,下面我们来看看它的源码。

1.首先,elementData是ArrayList实际保存对象的地方,是一个Object的数组,transient关键字表示这个数组不进行序列化。

2.构造器,默认的构造器会将一个上面一个默认的空数组被引用到我们的element上,这时候element是一个size为0的空数组,到触发了add方法,进行扩容操作。

除了默认的构造方法,还有一个可以声明初始数组大小的构造器。

我们还可以传入一个其它实现了Collection接口的入参,将这个Collection的值通过Arrays.copy方法复制到一个新的数组中。

Arrays.copy方法:入参分别是 original-原数组,新数组的长度,新数组的类型。

((Object)newType == (Object)Object[].class)/
//先判断传来的新数组类型和Object数组类型是否是内存中的同样一块,因为Class在虚拟机中只保存一块,如果类型相同,那么他们的Claas会==

如果是Object类型那么直接声明一个Object的新数组,如果不同那么调用底层的Array.newInstance方法生成一个新类型的数组。

注意:初生成的新数组,值都是null,需要使用

System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));

将原数组复制到新的数组中。

3.核心的add方法,在每次往ArrayList新增元素时,都会进行一个判断elmentData数组的大小进行扩容操作,三种情况:

空数组:

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY ==10
        }
        return minCapacity;
    }

往空数组里第一次插入数据,会返回一个默认的数组大小10,然后10-原数组长度>0时,执行grow方法,第一次插入,

 int oldCapacity = elementData.length;//第一次是0
 int newCapacity = oldCapacity + (oldCapacity >> 1);//0+0/2=0
if (newCapacity - minCapacity < 0)
     newCapacity = minCapacity;//那么第一次插入的默认数组长度就是10了

第二次扩容:往数组插入第11个数时,

 int oldCapacity = elementData.length;//这次原长度为10
 int newCapacity = oldCapacity + (oldCapacity >> 1);//10+10/2=15
 if (newCapacity - minCapacity < 0)
     newCapacity = minCapacity;//那么第一次插入的默认数组长度就是10了
 elementData = Arrays.copyOf(elementData, newCapacity);

每次扩容,新的数组长度都是之前的1.5倍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ArrayListJava集合框架中的一个类,它实现了List接口,可以用来存储一组对象,这些对象可以是任意类型。 下面是ArrayList源码解析: 1. 成员变量 ```java /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 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 = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; ``` ArrayList有三个成员变量,分别是DEFAULT_CAPACITY、EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA。DEFAULT_CAPACITY表示默认的容量大小,EMPTY_ELEMENTDATA是一个空数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA也是一个空数组,但它会在第一次添加元素时扩容为DEFAULT_CAPACITY大小。elementData是一个Object类型的数组,用于存储ArrayList中的元素,size表示ArrayList中元素的数量。 2. 构造方法 ```java /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // defend against c.toArray (incorrectly) not returning Object[] // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } ``` ArrayList提供了三个构造方法。第一个构造方法是无参的构造方法,它将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA。第二个构造方法接收一个Collection类型的参数c,它将参数c中的元素转为数组并将其赋值给elementData。第三个构造方法接收一个int类型的参数initialCapacity,它根据参数initialCapacity的值创建一个Object类型的数组并将其赋值给elementData。 3. 常用方法 常用方法包括add()、get()、set()、remove()、size()等。 add()方法用于在ArrayList中添加一个元素,如果elementData的容量不足,就需要进行扩容。扩容的方式是将elementData数组的大小增加50%。 get()方法用于获取ArrayList中指定位置的元素。 set()方法用于将ArrayList中指定位置的元素替换为指定的元素。 remove()方法用于删除ArrayList中指定位置的元素。 size()方法用于获取ArrayList中元素的数量。 4. 总结 ArrayListJava集合框架中的一个类,它实现了List接口,可以用来存储一组对象。ArrayList源码解析包括成员变量、构造方法和常用方法。掌握ArrayList源码可以帮助我们更好地理解它的实现原理,从而更加灵活地应用它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值