ArrayList源码

发布时间:2022-06-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了ArrayList源码脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

ArrayList

目录

  • 一、ArrayList

    • 1.1 包含的属性

    • 1.2 源码分析

      • 1.2.1 add源码分析

      • 1.2.2 grow源码

一、ArrayList

  • ArrayList中维护了一个Object数组:transient Object[] elementData; transient 表示该属性不会被序列化,ArrayList自己实现了wrITeObject方法和readObject方法

  • 当创建ArrayList对象时,如果使用的是无参构造,则初始的size为0,第一次添加时,则扩容为10,如需再次扩容,则扩容为原来的1.5倍

  • 如果使用的是指定大小的构造器,则初始化容量为指定大小,如需再次扩容,则直接扩容为1.5倍

1.1 包含的属性

ArrayList源码

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    @java.io.Serial
    PRivate static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认的容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 用于空实例的共享空数组实例。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 用于默认大小的空实例的共享空数组实例。 
       我们将其与 EMPTY_ELEMENTDATA 区分开来,以了解添加第一个元素时要膨胀多少。
       当使用无参构造方法时,将会将此实例赋值给elementData
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存储 ArrayList 元素的数组缓冲区。
       ArrayList 的容量就是这个数组缓冲区的长度。 
       当添加第一个元素时,任何具有 
       elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 
       都将扩展为 DEFAULT_CAPACITY。
     */
    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;
}

1.2 源码分析

1.2.1 add源码分析

    
 /**
 * ApPEnds the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    //修改次数+1
    modCount++;
    add(e, elementData, size);
    return true;
}

/**
 * 这个辅助方法从 add(E) 中分离出来,以将方法字节码大小保持在 35 以下
 (-XX:MaxInlineSize 默认值),这有助于在 C1 编译的循环中调用 add(E) 时。
 */
 //e-添加的元素,elementData-数组,s-当前数组的size
private void add(E e, Object[] elementData, int s) {
    //判断当前数组的size==数组的长度
    if (s == elementData.length)
        //真:扩容
        elementData = grow();
    //将当前元素加入集合
    elementData[s] = e;
    //size+1
    size = s + 1;
}

  • 首先判断当前数组的size==数组的长度,如果为首次添加元素,那么s和elementData.length都等于0,因此,会进入扩容方法

1.2.2 grow源码

private Object[] grow() {
    return grow(size + 1);
}

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 * @throws OutOfMemoryError if minCapacity is less than zero
 */
private Object[] grow(int minCapacity) {
    //存储当前数组的长度
    int oldCapacity = elementData.length;
    //旧长度>0||当前数组!=DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //真:计算新的@R_512_2050@,扩容为原来的1.5倍
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity, /* minimum growth */
                oldCapacity >> 1           /* preferred growth */);
         //以新容量创建数组
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
    //旧容量为0,当前数组==DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则创建默认容量的集合
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}


//ArraysSupport.newLength
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
    // assert oldLength >= 0
    // assert minGrowth > 0

    int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
    if (newLength - MAX_ARRAY_LENGTH <= 0) {
        return newLength;
    }
    //
    return hugeLength(oldLength, minGrowth);
}

📌可以看到再grow()方法中用到了ArraySupportArrays两个类,其中ArraySupport里面实现了很多方法来支持数组操作,包括查找两个数组的不匹配,以及为需要重新分配地址的数组计算新的长度。Arrays类里面实现了很多对数组进行操作的方法(比如排序、查找)Arrays.copyOf方法实现了将旧数组元素迁移到新的数组中,里面调用了System.arraycopy方法(native方法)实现

脚本宝典总结

以上是脚本宝典为你收集整理的ArrayList源码全部内容,希望文章能够帮你解决ArrayList源码所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。