Original Address: xeblog.cn/articles/19
This paper describes a realization of ArrayList in JDK8.
About ArrayList
ArrayList
Array is a queue, a internal maintenance Java数组
, and it is dynamic, the capacity of the array grows automatically. It inherits AbstractList
and implements List、RandomAccess、Cloneable、Serializable
interfaces.
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.
stackoverflow
Some people say the answer isJosh Bloch
(Java Collections Framework Author) design errors, the authors thought this design is valuable, but later found not.
- Easy to use Java Reflection to get all interfaces implemented method, because if not explicitly implemented
List
interfaces, reflecting the need to first obtaining interface when acquiring the parent class, then the parent class by obtaining interface. - Easy to glance
ArrayList
implementsList
the 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 int
constructor type parameter, it is passed in ArrayList
the 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 ArrayList
the actual size of the array or 0
, until only the first addition element for the default length of 10
array 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 ArrayList
how 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 ArrayList
capacity, 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 ArrayList
not 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 modCount
field to judge, modCount
field is the parent class AbstractList
field in each modification ArrayList
, the modCount
field is automatically incremented by 1, it will be time to initialize the iterator modCount
assigned iterator value expectedModCount
field. 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 expectedModCount
whether 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();
}
复制代码