ArrayList 源码详解

ArrayList

继承自AbstractList,实现了List、Cloneable、RandomAccess(随机访问,通常是常数时间)、Serializable共四个接口。其底层实现是数组,所以对数组下标的访问的速度是很快的。

源码解析


/**
*继承自AbstractList,实现了List、Cloneable、
*RandomAccess(随机访问,通常是常数时间)、Serializable共四个接口
*/
public class ArrayList<E> extends AbstractList<E>
		implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
	/**
	 * 实现了Serializable,序列号
	 */
	private static final long serialVersionUID = 8683452581122892189L;

	/**默认的初始容量10
	 * 
	 */
	private static final int DEFAULT_CAPACITY = 10;

	/**
	 * 用于空实例的共享空数组实例。
	 */
	private static final Object[] EMPTY_ELEMENTDATA = {};

	/**
	 * 数组缓冲区,arraylist的容量就是这个缓冲区的长度
	 */
	transient Object[] elementData; 

	/**
	 * ArrayList实际包含元素的数量
	 * 
	 */
	private int size;

	/**
	 * 带有初始容量大小的构造函数
	 */
	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);
		}
	}

	/**
	 * 空的构造函数,初始容量为10
	 */
	public ArrayList() {
		this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
	}

	/**
	 * 创建一个包含collection的构造函数,并且最后将collection向上转型为Object
	 * 
	 */
	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;
		}
	}

	/**
	 * 调整ArrayList实例的容量为当前大小。程序可以使用该方法来减少多余的存储空间
	 */
	public void trimToSize() {
		modCount++;
		if (size < elementData.length) {
			elementData = (size == 0)
			              ? EMPTY_ELEMENTDATA
			              : Arrays.copyOf(elementData, size);
		}
	}

	/**
	 * 增加ArrayList的容量,如果增加的小于默认最小的,则使用默认最小容量
	 * @param   minCapacity   the desired minimum capacity
	 */
	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(minCapacity);
		}
	}

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

	/**
	 * 数组的最大分配数量
	 */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

	/**
	 * 增加容量,以确保它可以至少持有由最小容量参数指定的元素的数目
	 * @param 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);
	}
	/**
	 * 根据最小容量判断返回容量(对比list极限容量)
	 */
	private static int hugeCapacity(int minCapacity) {
		if (minCapacity < 0) // overflow
			throw new OutOfMemoryError();
		return (minCapacity > MAX_ARRAY_SIZE) ?
		       Integer.MAX_VALUE :
		       MAX_ARRAY_SIZE;
	}

	/**
	 * Returns the number of elements in this list.
	 * 返回list中元素的个数
	 * @return the number of elements in this list
	 */
	public int size() {
		return size;
	}

	/**
	 * 判断list是否为空
	 */
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 是否包含元素o
	 */
	public boolean contains(Object o) {
		return indexOf(o) >= 0;
	}

	/**
	 * 返回元素所在位置
	 */
	public int indexOf(Object o) {
		if (o == null) {
			for (int i = 0; i < size; i++)
				if (elementData[i]==null)
					return i;
		} else {
			for (int i = 0; i < size; i++)
				if (o.equals(elementData[i]))
					return i;
		}
		return -1;
	}

	/**
	 * 数组中可能包含N个相同元素,返回从后查找出来的元素位置
	 */
	public int lastIndexOf(Object o) {
		if (o == null) {
			for (int i = size-1; i >= 0; i--)
				if (elementData[i]==null)
					return i;
		} else {
			for (int i = size-1; i >= 0; i--)
				if (o.equals(elementData[i]))
					return i;
		}
		return -1;
	}

	/**
	 * 进行浅克隆,元素并不被复制
	 */
	public Object clone() {
		try {
			ArrayList<?> v = (ArrayList<?>) super.clone();
			v.elementData = Arrays.copyOf(elementData, size);
			v.modCount = 0;
			return v;
		} catch (CloneNotSupportedException e) {
			// this shouldn't happen, since we are Cloneable
			throw new InternalError(e);
		}
	}

	/**
	 * 返回list中全部元素的数组形式
	 */
	public Object[] toArray() {
		return Arrays.copyOf(elementData, size);
	}

下边就是最常用的add、remove等操作了

/**
	 * Appends the specified element to the end of this list.
	 * 向尾部添加元素
	 * 这里要多说几句,很多人都是经常错误的比较 linkedlist和arraylist的add操作,比如循环的添加1千条数据
	 * 最后得到的结果却是arraylist更快一点,其实这种比较是错误的,arraylist的add方法其实是向尾部添加元素所以要快
	 * arraylist实现了random接口,访问是速度非常快的。但是随机存取的情况下,linkedList的速度其实是要更快的
	 * 然而就是这个操作其实才能对的上大家经常看的面试“圣经”里说的linkedList要更适用于频繁插入和删除
	 * 唠叨不嫌多,请记住ArrayList的底层实现是数组,而LinkList的底层实现是链表;
	 * 从ArrayList中随机删除一个对象,后面的数组排序就会朝前移位,这就是开销大的来处;而LinkList,
	 * 用的是链表,随机删除某一个,就将删除前的一个直接链接删除后的一个,而不要进行移位
	 * @param e element to be appended to this list
	 * @return <tt>true</tt> (as specified by {@link Collection#add})
	 *
	 */
	public boolean add(E e) {
		ensureCapacityInternal(size + 1);  // Increments modCount!!
		elementData[size++] = e;
		return true;
	}
	/**
	 * 指定位置插入元素(这个操作相当的耗时),尤其是System.arraycopy这个操作相当耗时
	 */
	public void add(int index, E element) {
		rangeCheckForAdd(index);

		ensureCapacityInternal(size + 1);  // Increments modCount!!
		System.arraycopy(elementData, index, elementData, index + 1,
		                 size - index);
		elementData[index] = element;
		size++;
	}

	/**
	 * 删除list中指定位置的元素,并将后边的元素向左移。(下标减1)
	 */
	public E remove(int index) {
		rangeCheck(index);

		modCount++;
		E oldValue = elementData(index);

		int numMoved = size - index - 1;
		if (numMoved > 0)
			System.arraycopy(elementData, index+1, elementData, index,
			                 numMoved);
		elementData[--size] = null; // clear to let GC do its work

		return oldValue;
	}

	/**
	 * 删除第一个指定的元素
	 */
	public boolean remove(Object o) {
		if (o == null) {
			for (int index = 0; index < size; index++)
				if (elementData[index] == null) {
					fastRemove(index);
					return true;
				}
		} else {
			for (int index = 0; index < size; index++)
				if (o.equals(elementData[index])) {
					fastRemove(index);
					return true;
				}
		}
		return false;
	}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值