ArrayList扩容详解

基于JDK1.8版本

ArrayList:底层数据结构是数组实现的,因此它的查询很快,增删却很慢,并且它是线程不安全的。

查看ArrayList源码,会发现ArrayList实现了List, RandomAccess, Cloneable, Serializable四个接口。

实现List接口支持了它的大部分功能

实现RandomAccess接口支持它可以快速随机访问元素(通过下标快速访问)。

实现Cloneable接口支持它可以被克隆。

实现Serializable接口支持它可以序列化,可以通过序列化传输。

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable

三种创建方式:

1、public ArrayList()
2、public ArrayList(int initialCapacity)
3、public ArrayList(Collection c)

第一种方式:

private static final int DEFAULT_CAPACITY = 10;//默认空间大小为10
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

无参数构建时,创建的ArrayList对象会默认空间大小为10,而且上面代码块种的element和DataDEFAULTCAPACITY_EMPTY_ELEMENTDATA都是空数组

第二种方式:

/**
 * Constructs an empty list with the specified initial capacity.
 */
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);
     }
}

当initialCapacity大于0时,创建一个大小为initialCapacity的数组

当initialCapacity等于0时,创建一个空数组

当initialCapacity小于0时,则抛出异常

第三种方式:

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
*/
public ArrayList(Collection 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;
        }
    }

该种方式是将一个集合转化成ArrayList,创建的对象的空间大小和导入的集合的大小一致

add()方法

/**
 * Appends the specified element to the end of this list.
 */
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal()方法

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//minCapacity=size+1;
//如果minCapacity大于当前集合的容量,如果大于就进行扩容
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
         grow(minCapacity);
}
//minCapacity=size+1;
//当elementData是空数组时,就返回初始大小10和minCapacity中较大的一个
//否则直接返回minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

grow()方法(扩容核心代码)

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);
}
//创建oldCapacity等于elementData数组的长度(原来的大小)
//创建newCapacity等于1.5倍的oldCapacity(左移一位相当于除于2)作为扩容后的大小
//当扩容后的大小仍小于minCapacity就使新的容量等于minCapacity
//当newCapacity大于MAX_ARRAY_SIZE(等于Integer的最大值减8),就使新的容量等于Integer的最大值
//elementData获取新的值

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

总的来说,每次扩容都是原来容量的1.5倍,直到Integer的最大值,由于是指数扩容,所以扩容到Integer的最大值需要不了多少次。

扩容实例(利用反射获取ArrayList中数组的长度):

package Arr;

import java.lang.reflect.Field;
import java.util.ArrayList;

public class test {
	public static void main(String[] args) throws Exception {
		test t = new test();
		ArrayList list = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			list.add(i);
		}
		System.out.println("10个元素  "+t.getlength(list));
		list.add(10);
		System.out.println("11个元素-进行扩容"+t.getlength(list));
		for(int i=0;i<5;i++) {
			list.add(i);
		}
		System.out.println("16个元素-进行扩容 "+t.getlength(list));
	}
    //获取list中数组的长度,及list的最大容量
	public int getlength(ArrayList list) throws Exception {
		Class li = list.getClass();
		Field filter = li.getDeclaredField("elementData");
		filter.setAccessible(true);
		Object[] o = (Object[]) filter.get(list);
		return o.length;
	}
}
/*输出结果:
 *
 *  10个元素  10
 *  11个元素-进行扩容15
 *  16个元素-进行扩容 22
 */

 

你可能感兴趣的:(java学习)