Foreword
In this article we analyze another container class, ArrayList, which implements the List interface, implementation class is List, the underlying implementation is an array, let us analyze in detail below. ps: some time ago because the school laboratory course set up all kinds of things plus a final exam, etc., for a long time did not update the blog ...
1. Overview
RandomAccess ArrayList class implements the interface, support random access.
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
复制代码
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;复制代码
2. Expansion
It should be noted that the expansion of the operation is also a thread unsafe operation. This line statement is not an atomic operation, so the problem of cross-border access the array will appear in a multithreaded environment. So ArrayList Like a HashMap is thread safe container .
elementData[size++] = e;复制代码
The following is a new element is inserted into the source code and expansion operations:
//插入新元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//这里会产生数组越界问题,因为下面这行语句并不是一个原子操作
elementData[size++] = e;
return true;
}
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 void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新容量为旧容量的1.5倍
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);
}复制代码
3. Removing elements
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;
}复制代码
4. fail-fast
About 4.1 fail-fast
fail-fast mechanism java collection (Collection) of one error mechanism. When multiple threads operating on the same set of content, it may generate fail-fast event.
For example: When a thread A iterator to traverse through a collection process, the content if the set is changed by the other thread; then thread A accesses the collection, an exception will be thrown ConcurrentModificationException generate fail-fast event.
fail-fast 4.2 ArrayList in
ArrayList modCount used to record the number of changes in the structure . Operation, or adjust the size of all the changes in the structure of the internal array means add or delete at least one element, set the value of the element just not a change in the structure.
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}复制代码
The sequence of
transient Object[] elementData; // non-private to simplify nested class access复制代码
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}复制代码
ArrayList list = new ArrayList();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(list);复制代码
6. Summary
ArrayList from the source point of view do have to be somewhat simpler than the HashMap some paper analyzes the internal data structure ArrayList with several commonly used methods, such as add (), remove (). It also discussed why a multi-threaded environment is a thread-safe container, if you want to use in a multithreaded environment, consider using Vector CopyOnWriteArrayList or two containers, also introduces the fail-fast in the ArrayList serialization issues of application and ArrayList.
Finally, I also welcome you to discuss with each other, pointing out the shortcomings of this article.