JDK1.7——ArrayList扩容机制

Posted 晚起的虫儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK1.7——ArrayList扩容机制相关的知识,希望对你有一定的参考价值。

ArrayList概述:

ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长。

ArrayList不是线程安全的,只能用在单线程环境下。

实现了Serializable接口,因此它支持序列化,能够通过序列化传输;

实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问;

实现了Cloneable接口,能被克隆。

ArrayList的构造方法:

private transient Object[] elementData;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final int DEFAULT_CAPACITY = 10;//默认长度是10

public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
}
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
}

关于elementData.getClass() != Object[].class 

这个地方很奇怪为什么要有这句话,看看具体的代码。

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

public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

  

确保内部容量:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//在java.lang.Integer类中常量MIN_VALUE、MAX_VALUE如下:
public static final int   MIN_VALUE = 0x80000000;//整型取值区间下界:-2147483648
public static final int   MAX_VALUE = 0x7fffffff;//整型取值区间上界:2147483647
//在java.util.AbstractList中modCount定义如下:
protected transient int modCount = 0;

public boolean add(E e) {
        //确保内部容量(通过判断,如果够则不进行操作;容量不够就扩容来确保内部容量)
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {//第一次运行将最小容量设置为10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//存在以AbstractList中,用于存放结构改变的次数。

        // 当插入元素位置大于数组最大容量,则扩容。
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}

ArrayList的具体实现代码(部分,但已经能说明原理):

package test;

import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private transient Object[] elementData;
    private int size;
    private static final int DEFAULT_CAPACITY = 10;
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
     public ArrayList(int initialCapacity) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
        }

        public ArrayList() {
            super();
            this.elementData = EMPTY_ELEMENTDATA;
        }

        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            size = elementData.length;
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } 
        
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
        
        private void ensureCapacityInternal(int minCapacity) {
            if (elementData == 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);
        }
        
        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);
        }
        
        private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
        
        public String toString() {
            Iterator<E> it = iterator();
            if (! it.hasNext())
                return "[]";

            StringBuilder sb = new StringBuilder();
            sb.append(‘[‘);
            for (;;) {
                E e = it.next();
                sb.append(e == this ? "(this Collection)" : e);
                if (! it.hasNext())
                    return sb.append(‘]‘).toString();
                sb.append(‘,‘);
            }
        }
        
        private class Itr implements Iterator<E> {
            
            int cursor = 0;

            int lastRet = -1;

            int expectedModCount = modCount;

            public boolean hasNext() {
                return cursor != size();
            }

            public E next() {
                checkForComodification();
                try {
                    int i = cursor;
                    E next = get(i);
                    lastRet = i;
                    cursor = i + 1;
                    return next;
                } catch (IndexOutOfBoundsException e) {
                    checkForComodification();
                    throw new NoSuchElementException();
                }
            }

            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();

                try {
                    ArrayList.this.remove(lastRet);
                    if (lastRet < cursor)
                        cursor--;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException e) {
                    throw new ConcurrentModificationException();
                }
            }

            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
        
        @Override
        public E get(int index) {
            rangeCheck(index);

            return elementData(index);
        }
        
        private void rangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
        
        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+size;
        }
        
        @SuppressWarnings("unchecked")
        E elementData(int index) {
            return (E) elementData[index];
        }
    
        @Override
        public int size() {
            return size;
        }
    
}

  

  

以上是关于JDK1.7——ArrayList扩容机制的主要内容,如果未能解决你的问题,请参考以下文章

20集合(List接口补充)

你知道的Go切片扩容机制可能是错的

ArrayList的扩容机制

Java 集合深入理解 :ArrayList源码解析,及动态扩容机制

ArrayList 扩容机制剖析

Java常见集合的默认大小及扩容机制