ArrayList的序列化与扩容

       ArrayList的底层实现是数组,与普通的数组相比,ArrayList能实现容量的动态增长。在ArrayList中最重要的属性是:
elementData和size。elementData是Object[]的数组,size是数组中实际元素的大小。

transient Object[] elementData;

private int size;

(一)序列化

       可以看到elementData被transient修饰了。transient用来说明elementData并不参与序列化的过程,而ArrayList是实现Serializable接口的,具体的序列化的过程在writeObject()和readObject()方法中,序列化的内容只取实际元素的元素(即size实际大小的元素)以减少io的损耗。以writeObject()为例:

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

(二)扩容

(1)什么时候扩容?
       以向ArrayList中添加元素的add()方法为例:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

       可以看到当minCapacity大于elementData的容量时,便开始扩容,而minCapacity是由size+1和DEFAULT_CAPACITY(默认10)的大者决定的。

(2)扩多大的容?

       先看下扩容的代码:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;  //(tag 1)
        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);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

       在上面的代码中,在tag 1之前newCapacity大小获取的思路是取minCapacity和oldCapacity扩大1.5倍(oldCapacity >> 1位移运算,计算的结果是oldCapacity的一半)的较大者。之后当newCapacity大于 MAX_ARRAY_SIZE时调用hugeCapacity()计算newCapacity新的值。其中MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8。在官方的说明中,减8是因为一些虚拟机保留头信息,减8可以减少出错的概率。在hugeCapacity中可以看到 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE :MAX_ARRAY_SIZE;,因此数组扩容后最大值依然为Integer.MAX_VALUE。

你可能感兴趣的:(集合,集合,ArrayList)