【源码阅读】ArrayList源码中EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA的作用

起因

就是看 ArrayList 源码时候注意了下 final 修饰的属性,于是乎发现了这么两个空数组
源码

    /**
     * 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 = {};

官方解释大概就是,EMPTY_ELEMENTDATA 用于空数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 用户默认数组的创建
不都是空的数组嘛,没看出来什么区别。。我们还是看看 ArrayList 怎么用的吧,从结果反推,嘿嘿…机智如我

EMPTY_ELEMENTDATA的使用

源码使用一

    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);
        }
    }

源码使用二

    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

源码使用三

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

从源码看有三个地方用了 EMPTY_ELEMENTDATA,两个是有参构造器一个序列化的过程
构造器上的注解其实也解释明白了,有参构造器时候取代一个空数组的建立,就是你传入的 initialCapacity 为 0 或者集合类为空的时候,复用 EMPTY_ELEMENTDATA 即可
那它作用就很明显了,为了减少空数组的建立,空数组大家共享一个嘛

DEFAULTCAPACITY_EMPTY_ELEMENTDATA的使用

源码使用一

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

源码使用二

    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            // ensureExplicitCapacity内部其实就是先modcount++,然后判断是不是需要调用grow扩容
            ensureExplicitCapacity(minCapacity);
        }
    }

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

源码使用三

    // 3. 这个方法在add,addAll,readObject时候会调用
    private void ensureCapacityInternal(int minCapacity) {
        // 1. 这里的elementData如果为空参构造器则等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 2. 这里保证了空参时候容量,即为10
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }


从源码看有三个地方使用了 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,一个空参构造器,两个是跟 Capacity 有关的方法
人家构造器也给你解释了,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是为了确保空参构造器时候是初始化容量为 10 的,怎么确认的看我注释吧…此外源码二好像就是外部开发人员用来扩容的,源码自己内部好像没用到
总结下作用就是,确保空参构造器时候初始化的容量等于 DEFAULT_CAPACITY,即 10

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值