ArrayList source record

Original Address: xeblog.cn/articles/19

This paper describes a realization of ArrayList in JDK8.

About ArrayList

ArrayListArray is a queue, a internal maintenance Java数组, and it is dynamic, the capacity of the array grows automatically. It inherits AbstractListand implements List、RandomAccess、Cloneable、Serializableinterfaces.

ArrayList UML

The advantages and disadvantages of ArrayList

advantage

  • Supports random access, since it is an internal array element is equal to the random access through array indices to access, the random element obtain high efficiency.
  • Elements are ordered (in order of addition).
  • Support automatic expansion (both an advantage and a disadvantage).

Shortcoming

  • Thread unsafe.
  • Automatic expansion of low efficiency, each expansion will need to add all elements to the new array.
  • Add and delete operations needed to move the elements in the array.

Question: Why ArrayList inheritance AbstractList then implements the List interface?

  • The answer I can not distinguish the authenticity of the content, but can dry out sun drying. stackoverflowSome people say the answer is Josh Bloch(Java Collections Framework Author) design errors, the authors thought this design is valuable, but later found not.

    stackoverflow.com/questions/2…

  • Easy to use Java Reflection to get all interfaces implemented method, because if not explicitly implemented Listinterfaces, reflecting the need to first obtaining interface when acquiring the parent class, then the parent class by obtaining interface.
  • Easy to glance ArrayListimplements Listthe interface (perfunctory .gif).
  • other...

ArrayList part of the field

/**
 * 默认容量为10
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 空数组 
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 用于默认大小的空数组。将此与EMPTY_ELEMENTDATA区分开来,以便在添加第一个元素时知道要膨胀多少。
 * 使用无参构造初始化ArrayList时默认的数组
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * 存储ArrayList元素的数组。添加第一个元素时,如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * 则此数组的长度是默认的10
 */
transient Object[] elementData;

/**
 * ArrayList的元素个数
 */
private int size;
复制代码

ArrayList Constructor

With a intconstructor type parameter, it is passed in ArrayListthe initial length

public ArrayList(int initialCapacity) {
	if (initialCapacity > 0) {
			this.elementData = new Object[initialCapacity];
	} else if (initialCapacity == 0) {
			// 默认的空数组 Object[] EMPTY_ELEMENTDATA = {}
			this.elementData = EMPTY_ELEMENTDATA;
	} else {
			throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
	}
}
复制代码

JDK8 no arguments constructor

public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
复制代码

JDK7 no arguments constructor

public ArrayList() {
	this(10);
}
复制代码

JDK8 initialized using the default constructor with no arguments ArrayList, the delay optimization done, is not performed add()before the method of ArrayListthe actual size of the array or 0, until only the first addition element for the default length of 10array initialization.

Passing a collection object constructor, a construct that contains the collection of elementsArrayList

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 is how to achieve dynamic growth?

First look at the add(E e)method

public boolean add(E e) {
	// 判断添加此元素时数组是否会超出,超出则增长数组
	ensureCapacityInternal(size + 1);
	// 添加元素
	elementData[size++] = e;
	return true;
}
复制代码
/**
 * 此方法用于判断当添加这个元素时数组容量是否超出,超出则自动增长
 */
private void ensureCapacityInternal(int minCapacity) {
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
	// 如果数组是通过默认构造方法实例化的,elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 将返回true
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
			// 返回最大的值 ,如果minCapacity大于10则返回minCapacity的值
			return Math.max(DEFAULT_CAPACITY, minCapacity);
	}
	return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
	// fail-fast机制,并发修改会抛出异常 throw new ConcurrentModificationException()
	modCount++;

	// overflow-conscious code
	if (minCapacity - elementData.length > 0)
			// 新增元素后的数组长度超过了当前数组长度,所以调用增加数组长度的方法
			grow(minCapacity);
}
复制代码

Take a look at grow(int minCapacity)the method will be able to know ArrayListhow to automatically increase the capacity of the

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

private void grow(int minCapacity) {
	// overflow-conscious code
	int oldCapacity = elementData.length;
	// 增长后的容量等于旧容量的1.5倍
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if (newCapacity - minCapacity < 0)
			newCapacity = minCapacity;
	 // MAX_ARRAY_SIZE为int的最大值减8,如果增长后的容量超过该值,则直接返回int的最大值,否则返回该值
	if (newCapacity - MAX_ARRAY_SIZE > 0);
			newCapacity = hugeCapacity(minCapacity);
	// 使用的是Arrays.copyOf()方法将原数组中的元素拷贝到新增数组中,新增数组的长度即是newCapacity
	elementData = Arrays.copyOf(elementData, newCapacity);
}
复制代码

Here are hugeCapacity(int minCapacity)methods

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

JDK6 the int newCapacity = (oldCapacity * 3)/2 + 1;growth capacity is equal to the capacity of the old doubly 1.5 1, JDK8 bitwise using direct growth of 1.5 times the capacity of the old.

ArrayList manually adjust the volume

Before adding a large number of elements, by calling ensureCapacity(int minCapacity)to the manual method of increasing ArrayListcapacity, to reduce the number of incremental reallocation

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);
	}
}
复制代码

trimToSize()ArrayList methods may be adjusted to the capacity of the actual element size

public void trimToSize() {
	modCount++;
	if (size < elementData.length) {
			elementData = (size == 0)
				? EMPTY_ELEMENTDATA
				: Arrays.copyOf(elementData, size);
	}
}
复制代码

fail-fast mechanism

Because ArrayListnot thread safe, so if there are other threads in the process of using an iterator's modified ArrayList, it will throw an throw new ConcurrentModificationException()exception, which is fail-fast机制(fail-fast).
fail-fast机制Through the modCountfield to judge, modCountfield is the parent class AbstractListfield in each modification ArrayList, the modCountfield is automatically incremented by 1, it will be time to initialize the iterator modCountassigned iterator value expectedModCountfield. ArrayList iterator internal implementation (part)

public Iterator<E> iterator() {
	return new Itr();
}
		
private class Itr implements Iterator<E> {
	int cursor;       // index of next element to return
	int lastRet = -1; // index of last element returned; -1 if no such
	int expectedModCount = modCount;

	Itr() {}

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

	@SuppressWarnings("unchecked")
	public E next() {
		checkForComodification();
		int i = cursor;
		if (i >= size)
				throw new NoSuchElementException();
		Object[] elementData = ArrayList.this.elementData;
		if (i >= elementData.length)
				throw new ConcurrentModificationException();
		cursor = i + 1;
		return (E) elementData[lastRet = i];
	}

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

		try {
				ArrayList.this.remove(lastRet);
				cursor = lastRet;
				lastRet = -1;
				expectedModCount = modCount;
		} catch (IndexOutOfBoundsException ex) {
				throw new ConcurrentModificationException();
		}
	}
}
复制代码

In the execution next()、remove()time of the method calls the checkForComodification()method to determine expectedModCountwhether or not also equal to modCount, if not equal then the other thread has changed ArrayList, then it will throw an exception throw new ConcurrentModificationException().

final void checkForComodification() {
	if (modCount != expectedModCount)
			throw new ConcurrentModificationException();
}
复制代码

To be added. . .

Guess you like

Origin juejin.im/post/5cfc9c636fb9a07eb74b2f52