集合
List
ArrayList
- ArrayList 初始化底层
- ArrayList 无参构造方法
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
/**
* transient关键字只能修饰变量,而不能修饰方法和类。
* 一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
elementData
是一个存储 ArrayList 的数组缓存区,ArrayList的容量就是该数组缓存区长度。
当添加第一个元素时,任何具有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都将扩展为 DEFAULT_CAPACITY
- ArrayList 有参构造方法
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
ArrayList 无参构造方法中,会初始化一个默认空的数组
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
ArrayList 有参构造方法中,会更具形参
initialCapacity
分配一个指定容量大小的数组
- ArrayList 添加元素的底层实现
- ArrayList 的add方法
/**
* Appends the specified element to the end of this list.
*
* @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;
}
private void ensureCapacityInternal(int minCapacity) {
//最小的当期容量与原有数组容量对比
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断原有元素集合 elementData 是否是之前为指定容量的无参初始化的 数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果当前超过当前数组默认容量 10 则返回当前的扩容后的空间
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//返回当前最新的扩容后的空间
return 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:
//完成数组的扩容copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
======================================================================================================
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* A constant holding the maximum value an {@code int} can
* have, 2<sup>31</sup>-1.
*/
@Native public static final int MAX_VALUE = 0x7fffffff;
=====================================================================================================
- ArrayList 获取元素的底层实现
- ArrayList get方法
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
/**
* Checks if the given index is in range. If not, throws an appropriate
* runtime exception. This method does *not* check if the index is
* negative: It is always used immediately prior to an array access,
* which throws an ArrayIndexOutOfBoundsException if index is negative.
*/
private void rangeCheck(int index) {
//检查获取的元素下标是否越界
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
@SuppressWarnings("unchecked")
E elementData(int index) {
//之间根据数组的下标查找元素
return (E) elementData[index];
}
- ArrayList 更新元素的底层实现
- ArrayList set方法
/**
* Replaces the element at the specified position in this list with
* the specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
//访问元素下标越界检查
rangeCheck(index);
//返回修改之前的元素
E oldValue = elementData(index);
//之间通过数组索引修改元素
elementData[index] = element;
return oldValue;
}
* ArrayList 总结
初始化:
-
当通过无参构造创建 ArrayList 对象的时候
ArrayList 的底层会 默认一个已经在对象内部存在的空 Object 数组
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
(该数组是为指定初始默认大小的),交给与当前对象的数组缓存区this.elementData
-
通过有参构造器创建 ArrayList 对象的时候
ArrayList 的底层会 通过形参参数创建一个新的 Object 空数组,并初始化数组长度为形参参数,同时将该 Object 数组交给当前
对象的数组缓存区
this.elementData
-
区别:
- 无参直接使用内部已经存在的空数组,有参会重新创建新的空数组
- 无参的空数组的长度为指定(在第一次调用put方法时会指定),有参的空数组的长度在创建时就已经指定(长度为形参长度)
元素的添加更新:
-
添加元素:
- 添加元素时会调用
ensureCapacityInternal
,将当前的元素个数记录值size
+1,作为ensureCapacityInternal
最小容量的中间变量minCapacity
。 - 在
calculateCapacity
方法中判断当前的对象中原有的elementData
对象是否与初始化时的分配的DEFAULTCAPACITY_EMPTY_ELEMENTDATA
一致- 如果相同(调用无参构造创建的ArrayrList对象),就直接返回当前已经存入的元素个数的最小容量(
minCapacity
)与 默认数组大小(DEFAULT_CAPACITY
=10)中的最大值 - 如果不一致(调用有参构造创建的ArrayrList对象),返回当前最小容量
minCapacity
- 如果相同(调用无参构造创建的ArrayrList对象),就直接返回当前已经存入的元素个数的最小容量(
- 此时调用
grow
方法开始对数组扩容,这里对于无参的构造对象创建的 ArrayList 就会第一次初始化数组长度(length 10) - 在
grow
方法中,会先有一个有一个旧容量oldCapacity
,该容量来自于elementData.length
,newCapacity
为旧容量的 1.5 倍(newCapacity = oldCapacity + (oldCapacity >> 1)
) - 然后利用
Arrays.copyOf(elementData, newCapacity)
实现数组拷贝扩容
- 添加元素时会调用
-
获取元素
- 判断索引下标是否越界,越界抛出异常,否则直接通过数组的下标索引获取元素
-
修改元素
- 直接通过索引的下标返回被修改的值,通过索引对元素修改