ArrayList集合
一、ArrayList集合底層數據結構
1.1ArrayList集合的介紹
- List接口的可調整大小的數組實現
- 數組:一旦初始化長度就不可以發生改變
1.2 數組結構介紹
- 增刪慢:每次刪除元素,都需要更改數組長度、拷貝以及移動過元素位置.
- 查詢快:由于數組在内存中是一塊連續空間,因此可以根據地址+索引的方式快速獲取對應位置上的元素.
二、ArrayList三種構造方法源碼分析
2.1構造方法
Constructor | Constructor描述 |
---|---|
ArrayList() | 构造一个初始容量为十的空列表 |
ArrayList(int initialCapacity) | 构造具有指定初始容量的空列表 |
ArrayList(Collection<? extends E> c) | 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的 顺序" |
2.2 案例演示
2.2.1 空參構造
public class Test01 {
public static void main(String[] args) {
//这行代码做了什么?
//真的构造一个初始容量为十的空列表?
ArrayList<String> list = new ArrayList<String>();
}
}
源碼分析:
public class ArrayList<E> {
/**
* 默认初始容量
*/
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;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
}
結論:
通过空参构造方法创建集合对象并未构造一个初始容量为十的空数组,而是将DEFAULTCAPACITY_EMPTY_ELEMENTDATA地址赋值给elementData.
2.2.2 指定容量的構造ArrayList(int initialCapacity)
public class Test01 {
public static void main(String[] args) {
//这行代码ArrayList底层做了什么?
ArrayList<String> list = new ArrayList<String>(5);
}
}
源碼分析
public class ArrayList<E> {
//initialCapacity = 5
public ArrayList(int initialCapacity) {
//判断初始容量initialCapacity是否大于0
if (initialCapacity > 0) {
//创建一个数组,且指定长度为initialCapacity
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果initialCapacity容量为0,把EMPTY_ELEMENTDATA的地址赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
//以上两个条件都不满足报错
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
}
結論:
根據ArrayList集合的構造方法創建一個指定容量的數組.
2.2.3带参构造集合ArrayList(Collection<? extends E> c)
運行代碼:
public class Test03 {
public static void main(String[] args) {
//ArrayList(Collection <? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭 代器返回的顺序。
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//这行代码做了什么?
ArrayList<String> list1 = new ArrayList<>(list);
for (String s : list1) {
System.out.println(s);
}
}
}
源碼分析:
public class ArrayList<E> {
//长度为0的空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//集合存元素的数组
Object[] elementData;
//集合的长度
private int size;
public ArrayList(Collection<? extends E> c) {
//将构造方法中的参数转成数组
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 再次进行判断
if (elementData.getClass() != Object[].class)
// 数组的创建和拷贝
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 就把空数组的地址赋值给集合存元素的数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
//将集合转数组的方法
public Object[] toArray() {
//调用数组工具类的方法
return Arrays.copyOf(elementData, size);
}
}
public class Arrays {
public static <T> T[] copyOf(T[] original, int newLength) {
//再次调用方法得到一个数组
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
//不管三元运算符的结果如何,都会创建一个新的数组
//新数组的长度一定是和集合的size一样
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
//数组的拷贝
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
//返回新数组
return copy;
}
}
以上就是分享的ArrayList集合的三個構造方法及底層源碼的解析,希望可以幫助到需要的小夥伴們.