ArrayList
底层结构和源码分析
ArrayList
继承关系图和构造器
构造器
Constructor and Description |
---|
ArrayList() 构造一个初始容量为十的空列表。 |
ArrayList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 |
ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。 |
常用方法
boolean | add(E e) 将指定的元素追加到此列表的末尾。 |
---|---|
void | add(int index, E element) 在此列表中的指定位置插入指定的元素。 |
boolean | addAll(Collection<? extends E> c) 按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。 |
boolean | addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到此列表中,从指定的位置开始。 |
void | clear() 从列表中删除所有元素。 |
E | get(int index) 返回此列表中指定位置的元素。 |
---|---|
int | indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 |
boolean | isEmpty() 如果此列表不包含元素,则返回 true 。 |
Iterator<E>** ** | iterator() 以正确的顺序返回该列表中的元素的迭代器。 |
int | lastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。 |
E | remove(int index) 删除该列表中指定位置的元素。 |
---|---|
boolean | remove(Object o) 从列表中删除指定元素的第一个出现(如果存在)。 |
boolean | removeAll(Collection<?> c) 从此列表中删除指定集合中包含的所有元素。 |
E | set(int index, E element) 用指定的元素替换此列表中指定位置的元素。 |
---|---|
int | size() 返回此列表中的元素数。 |
List<E> | subList(int fromIndex, int toIndex) 返回此列表中指定的 fromIndex (包括)和 toIndex 之间的独占视图。 |
---|---|
Object[] | toArray() 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 |
<T> T[] | toArray(T[] a) 以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。 |
ArrayList
源码分析
使用是ArrayList
的无参构造创建对象
ArrayList<String> integers = new ArrayList<>();
for (int i = 0; i < 3; i++) {
integers.add("A_"+i);
}
源码分析:
1.先创建一个 ArrayList 对象 并完成初始化大小为0,当第一次添加元素时,扩容为10大小,以后扩容时,按照1.5倍扩容
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 创建一个空数组
transient Object[] elementData; 为null 说明ArrayList底层是维护了一个 elementData 数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;将空数组赋给 elementData
所以使用是无参构造创建 ArrayList 对象时 开始大小是 0
}
2.添加元素
private int size; // 当集合中没有元素时 size 为 0
public boolean add(E e) {
在添加前先确定当前容量是否能够添加一个元素
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e; 将当前的元素添加到elementData数组指定索引的位置
return true;
}
3.确保当前的容量大小
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
如果是第一次添加时,先确定elementData是否是一个空数组,则 if 语句成立,将返回一个 DEFAULT_CAPACITY 的值就是 10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
确保是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++; 记录当前ArrayList集合被修改的次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
扩容代码如下
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; 第一次添加时 elementData是0
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);
}
所以结论是:当使用无参构造器创建对象时,第一次添加时,扩容的大小为10,当再次扩容时,按照以前的1.5倍
使用是ArrayList
指定大小的有参构造创建对象
ArrayList<String> integers = new ArrayList<>();
for (int i = 0; i < 3; i++) {
integers.add("A_"+i);
}
transient Object[] elementData; 为null 说明ArrayList底层是维护了一个 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);
}
}
2.添加元素
private int size; // 当集合中没有元素时 size 为 0
public boolean add(E e) {
在添加前先确定当前容量是否能够添加一个元素
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e; 将当前的元素添加到elementData数组指定索引的位置
return true;
}
3.确保当前的容量大小
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
如果是第一次添加时,先确定elementData是否是一个空数组,则 if 语句成立,将返回一个 DEFAULT_CAPACITY 的值就是 10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
确保是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++; 记录当前ArrayList集合被修改的次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
扩容代码如下
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; 第一次添加时 elementData是0
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);
}
如果使用的是指定大小的构造器,则初始 elementData 容量为指定大小,如果需要扩容,则直接扩容 elementData 为 1.5 倍
ArrayList
的注意事项:
1.ArrayList
集合可以存放任意数据,包括null
类型,并且是可以存在多个
2.ArrayList
是由数组来实现数据存储的
3.ArrayList
基本等同于Vector
,除了ArrayList
是线程不安全的【执行效率高】,在多线程情况下,不建议使用ArrayList
ArrayList
的底层操作机制源码分析【必须掌握】
结论:
1.ArrayList
中维护了一个Object
类型的数组elementData
。transient Object[] elementData;
transient
表示瞬间,短暂的,表示该属性不会被序列号
2.当创建ArrayList
对象时,如果使用的是无参构造,则被始elementData
容量为0,第1次添加,则扩容elementData
为10,如需要再次扩容,则扩容elementData
为1.5倍
3.如果使用的是指定大小的构造器,则初始elementData
容器为指定大小,如果需要扩容,则直接扩容elementData
为1.5倍
ArrayList
的底层操作机制分析案例
ArrayList list = new ArrayList();
//ArrayList list = new ArrayList();
for(int i=1;i<=10;i++){
list.add(i);
}
for(int i=11;i<=15;i++){
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);
for(Object object:list){
System.out.println(object);
}
注意:1.先看效果,2.再追源码
使用无参构造器创建ArrayList数组【底层源码】
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};// 是一个空数组
执行流程: