Article directory
1. Overview of ArrayList
ArrayList
It is a commonly used data structure in the Java collection framework, and its bottom layer is implemented based on arrays. The size of the array is fixed, but ArrayList
the capacity expansion mechanism can realize the dynamic change of the capacity.
The capacity of the array is determined at the time of definition. If the array is full and then inserted, the array will overflow. Therefore, when inserting, it will first check whether expansion is required. If the current capacity + 1 exceeds the length of the array, expansion will be performed.
ArrayList
The expansion is to create a new array of 1.5 times , and then copy the value of the original array.
ArrayList
There are two ways to add elements
public boolean add(E e)
public boolean addAll(Collection<? extends E> c)
The following source code analysis
2. Source code analysis of ArrayList construction method
When a collection is created ArrayList
, its constructor is called
//存放元素的数据
transient Object[] elementData;
//默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
//集合长度
private int size;
//无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//指定元素长度构造
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);
}
}
//构造参数为集合
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
- No-argument construction: No-argument construction will use
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
an array as the data to store elements, that is, the length of the array at the bottom of the default collection is 0. - Specified element length construction: The specified element length construction uses the construction parameter
initialCapacity
as the length of the array.this.elementData = new Object[initialCapacity];
- The construction parameter is a collection: use
c
the length of the construction parameter collection aselementData
the length of the underlying array, and copy the elements of the collection into a new array and assign it toelementData
3. ArrayList.add() source code analysis
First prepare a piece of code for adding data, the length of the added data is 15.
public class TestArrayList {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 15; i++) {
list.add(i);
}
}
}
First, ArrayList
when creating a collection, its no-argument construction method is called, and ArrayList
the underlying array is an empty array with a length of 0.
The following is add
the source code of the method
public boolean add(E e) {
//检查是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
Before adding elements into the collection, you need to call ensureCapacityInternal
the method to check whether to expand.
The parameter is the length of the array of underlying storage data + 1
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
ensureCapacityInternal
inside ensureExplicitCapacity
method.
Before execution, a method ensureExplicitCapacity
needs to be called calculateCapacity
to calculate the length that needs to be expanded.
//默认的初始化容量大小
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
calculateCapacity
The method has two parameters, elementData
which are the underlying array used to store data, and minCapacity
the new array length.
In this method, first judge elementData
whether it is the default empty array (that is, whether it is DEFAULTCAPACITY_EMPTY_ELEMENTDATA
the same object) **, if so, take the maximum value of the length of the new array and the length of the default initialization capacity and return. **That is to say, if an element is added to the collection for the first time, the default capacity is 10.
If it is not the default empty array, it will minCapacity
return the new array length.
//该参数是记录列表结构以被修改的次数
protected transient int modCount = 0;
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
Then compare the size of the current new array length minCapacity
with the underlying array lengthelementData.length
If minCapacity
it is less than or equal to elementData.length
, no expansion is required.
If minCapacity
it is larger elementData.length
, it needs to be expanded and grow(minCapacity)
the method is called.
The parameter is the length of the new array.
//数组最大容量,-8是因为有些VM会在数组中保留一些词
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
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);
}
This grow
method is the key to expansion.
The key to the length of the expanded array is this line of code
int newCapacity = oldCapacity + (oldCapacity >> 1);
(oldCapacity >> 1)
It is the right shift operation that means dividing by 2
Assuming that it is 10 now oldCapacity
, its original code is 1010, moving one bit to the right is 0101, which is also 5.
So the new capacity after expansion newCapacity
is 15.
Then judge the expanded capacity and compare newCapacity
it with the capacity of the new array .minCapacity
- If it is less than, that is, the expanded capacity
newCapacity
is not enough, then assign the length of the new arrayminCapacity
tonewCapacity
.
Then compare the expansion capacity newCapacity
with the maximum capacity of the arrayMAX_ARRAY_SIZE
- If greater than, execute
hugeCapacity(minCapacity)
the method
//数组最大容量,-8是因为有些VM会在数组中保留一些词
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
hugeCapacity(minCapacity)
The method judges that if the minimum extension requirement value is less than 0, an exception is thrown; otherwise, it is judged minCapacity
whether the minimum extension requirement value is greater than MAX_ARRAY_SIZE
, and if it is greater, returns int
the maximum value , and if not, returns MAX_ARRAY_SIZE
the value.
Finally, Arrays.copyOf(elementData, newCapacity);
the expansion is completed.
4. ArrayList.addAll() source code analysis
Prepare a piece of test code first.
public class TestArrayList {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
}
}
The following is addAll
the source code of
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
addAll
The main logic is to convert the incoming collection into an array and get the length of the array.
Then ArrayList
check and expand the current operation, and then System.arraycopy
the method System.arraycopy
appends the array to the subscript elementData
of the array , then sets the size, and finally returns the addition status according to the length of the incoming container.size
size
5. Summary
ArrayList
The expansion is usually 1.5 times the size of the original array, andArrayList
the maximum capacity isint
the maximum value.addAll(Collection c)
When there is no element, the expansion isMath.max(10, 实际元素个数)
, and when there is an element, it isMath.max(原来容量的1.5倍,实际元素个数)
add(Object o)
The first expansion is 10, and the second expansion is 1.5 times the previous capacity.ArrayList(int initialCapacity)
will use an array with the specified capacityArrayList(Collection<? extends E> c)
Will use the size of c as the array capacity