ArrayList的成员变量

我们现在来看ArrayList的成员变量,在上一篇博客中我们探究了Arraylist的最大容量,下面我们来看看其他的成员变量。

  1. size
    /**
     * The size of the ArrayList (the number of elements it contains).
     * ArrayList的大小(它包含的元素数)。
     * @serial
     */
    private int size;

此成员变量是用来描述ArrayList的大小的
java的成员变量是有默认值的,这也是为什么ArrayList中没有对size初始化的代码,但是却可以直接使用的原因。以下内容可以作为了解

//下面是在类中定义的成员变量
private boolean bool;//默认值是false
private byte bt;//默认值是0
private short st;//默认值是0
private char ch;//默认值是空字符('\u0000')
private int  i;//默认是0
private long l;//默认是0
private float f;//默认是0.0
private double d;//默认是0.0
private String str;//默认是null

2.static final int DEFAULT_CAPACITY

    /**
     * Default initial capacity.
     * 默认初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;

此静态成员变量的定义用来作为默认初始容量,用于在ArrayList中使用,但并不是指Arraylist在new出来时容量就是10,这个后续会有解释。

  1. static final Object[] EMPTY_ELEMENTDATA = {}即static final Object[] EMPTY_ELEMENTDATA = new Object[0]。还有static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}即static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
    /**
     * 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的值是相同的,那么为什么要定义这两个成员变量呢?看到DEFAULTCAPACITY_EMPTY_ELEMENTDATA的注释解释是我们将其与空元素数据区分开,以知道何时充气添加第一个元素。这是什么意思呢,我们来看一下下面几个方法,包含2个构造函数和一个计算容量的方法

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

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

可以发现当你使用带参的构造函数指定初始数组的长度时,如果长度为0,那么会使用EMPTY_ELEMENTDATA,当你是否不带参的构造函数时,使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
而在对数据进行操作是,比如add一个元素时会调用calculateCapacity方法计算容量,如果elementData 为DEFAULTCAPACITY_EMPTY_ELEMENTDATA就返回容量为DEFAULT_CAPACITY 也就是上面提的到一个成员变量,置位10。
但是如果elementData 不为DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,返回的容量便是minCapacity。
我们以下面为例

ArrayList list1 = new ArrayList(0);
ArrayList list2 = new ArrayList();
//则list1.elementData为EMPTY_ELEMENTDATA
//而list2.elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA

那么我们在调用add方法时,可以知道list1的容量扩展为1,而list2扩容为10.

public boolean add(E e) {
   ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

我们可以看到,上面方法中使用了成员变量elementData进行了对比。elementData也是我们要看的最后一个成员变量

  1. 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.
     * 存储ArrayList元素的数组缓冲区。ArrayList的容量是这个数组缓冲区的长度。
     * 任何elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList
     * 当添加第一个元素时,将扩展到DEFAULT_CAPACITY的容量。
     */
    transient Object[] elementData; // non-private to simplify nested class access

这也是ArrayList的主要操作对象,我们往集合中添加和操作元素时实际上就是对数据elementData的操作。
可以发现elementData被transient 修饰,这个修饰符是防止序列化时java自带的序列化对没有填满的数组中,未填充部分进行序列化的操作而添加的。不过ArrayList中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。这个只实现会在后续整理。
至此,ArrayList中的成员变量整理结束,有意思的点就是ArrayList的最大容量,EMPTY_ELEMENTDATA 与DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为什么内容相同还要定义2个成员变量,以及不同构造函数下,添加第一个元素时,Arraylist扩容的容量探究。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值