当前位置:网站首页>ArrayList源码解析
ArrayList源码解析
2022-06-28 13:47:00 【u012804784】
优质资源分享
| 学习路线指引(点击解锁) | 知识定位 | 人群定位 |
|---|---|---|
| 🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
| Python量化交易实战 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
在平时Java,存储数据需要用到列表,而大多时候都能用到ArrayList,比如Mybatis查询数据列表,返回列表都是ArrayList,很多数据的存放也用到了ArrayList。
jdk 版本: 1.8
ArrayList 是基于大小可变的数组实现,并允许添加null值, 根据下标就能数据查询快。数组一旦初始化就确定好了大小,如果需要添加数据,就需要做数据的复制,这些操作比较耗时。
数组拷贝
ArrayList数组的扩容、添加和删除需要用到数组的拷贝,主要用到了以下两个方法:
System.arraycopyArrays.copyOf
System.arraycopy
System.arraycopy() 是Java的原生的静态方法,该方法将源数组元素拷贝到目标数组中去。
参数详解:
- src 源数组
- srcPos 源数组拷贝的起始索引
- dest 目标数组
- destPos 拷贝到目标数组的起始索引
- length 拷贝元素的个数
将src源数组,起始索引为srcPos,个数为length,复制到起始索引为destPos的dest目标数组。
比如:
int[] srcArray = new int[]{1,2,3,4,5,6};
int[] desArray = new int[5];
System.arraycopy(srcArray,1,desArray,2,3);
System.out.println("desArray: " + Arrays.toString(desArray));
输出:
[0, 0, 2, 3, 4]
Arrays.copyOf
Arrays.copyOf本质也是调用System.arraycopy方法:
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
首先创建一个新的数组copy,将original数组全部复制给copy数组。
主要字段:
// 底层数组
transient Object[] elementData;
// 数组个数大小
private int size;
// 默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
ArrayList是基于数组的一个实现,elementData就是底层的数组。size是记录数组的个数。
构造方法
ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
无参构造方法,创建数据直接赋值一个空数组。
ArrayList(int initialCapacity)
赋一个初始化容量initialCapacity:
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);
}
}
- 初始化容量
initialCapacity大于零,新建长度initialCapacity的数组。 - 初始化容量
initialCapacity等于零,新建一个空数组。
添加数据
添加数据有两个方法:
- add(E e) 直接添加在数组尾部。
- add(int index, E element) 根据下标添加数据。
add(E e)
在列表尾部添加数据:
/**
* Appends the specified element to the end of this list.
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal 判断添加数据后的容量是否足够,如果不够,做扩容操作。
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY\_EMPTY\_ELEMENTDATA) {
return Math.max(DEFAULT\_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
ensureCapacityInternal 作用是判断容量当前容量是否足够存放新的数据,如果不够就做扩容操作。
calculateCapacity计算容量,如果数组为null,返回minCapacity和10的最大值,否则返回minCapacity。这个方法就是返回数组的大小。
调用无参构造方法
ArrayList(),再调用add()方法,首先数组容量会变成10。这也是为什么无参构造方法ArrayList()上面有会有注解Constructs an empty list with an initial capacity of ten.
ensureExplicitCapacity 判断需要的容量minCapacity大于当前数组的长度elementData.length,将会做扩容处理,也是调用grow方法:
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);
// 拷贝数组到新的长度数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
group 主要做了两件事:
- 长度扩大到原来的 1.5倍
- 拷贝数组到新长度的数组
做完判断是否要做扩容之后,直接在size位置上赋值要添加的元素,然后size再自增。
elementData[size++] = e;
add(E e)流程总结
- 判断数据容量是否足够,如果是空数组,返回
10,其他容量返回当前数组size + 1。 - 返回容量和当前数组长度对比,小于做扩容处理。
- 扩容长度为原来长度的
1.5倍,将数组赋值给长度为原来数组1.5倍的新数组。 - 在数组的最末尾
size赋值。
add(int index, E element)
此添加数据是在指定的下标添加数据。
public void add(int index, E element) {
// 下标是否越界
rangeCheckForAdd(index);
// 判断是否要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 复制i到size的数据到i+1 到size +1
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
add(int index, E element) 在index下标添加数据,
- 首先判断
index是否在0 ~size之间。 - 判断是否要扩容,需要扩容,进行
1.5倍扩容。 - 数据迁移,把
index以后的数据全部往后移动一位。 - 赋值
index下标数据。

获取数据
获取数据只有通过数组下标获取数据 get(int index):
public E get(int index) {
//检查是否超过数组范围
rangeCheck(index);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
// 通过下标获取数据
return (E) elementData[index];
}
这里获取数据就比较简单:
- 检查下标是否超过数组范围。
- 通过下标访问数据。
删除数据
remove(Object o)
删除列表中第一个匹配的元素:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
判断要删除数据是否为null:
- 为空,判断
elementData[index]是否为空。 - 不为空,判断元素
equals是否匹配elementData[index]。
上面判断都为true时,调用fastRemove方法:
private void fastRemove(int index) {
modCount++;
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
}
移动数组数据,index+1 以及之后的数据往前移动一位,最后一位size-1赋值为null。

remove(int index)
根据index下标删除数据。
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;
}
总结
- 数组的扩容、添加和删除都需要用到
System.arraycopy方法,System.arraycopy是将src源数组,起始索引为srcPos,个数为length,复制到起始索引为destPos的dest目标数组。 ArrayList主要是基于Object[] elementData动态数组实现。- 调用构造方法,无参的就赋值一个空数组,有初始容量的就赋值一个初始容量。
add添加数组首先判断是否需要扩容,需要扩容,长度扩大成原来的1.5倍。- add(E e) 在
size赋值添加数据 - add(int index, E element) 将数组从
index往后移动一位,新数据添加到index上。
- add(E e) 在
- 获取数据
get(int index)利用数组的特定,根据下标获取数据。 remove(int index)将index之后的数据全部往前移动一位,size - 1赋为null。
边栏推荐
- How fragrant! The most complete list of common shortcut keys for pychar!
- Oracle cloud infrastructure extends distributed cloud services to provide organizations with greater flexibility and controllability
- 如何备份mysql_史上最全的MYSQL备份方法
- 恒生电子:金融分布式数据库LightDB通过中国信通院多项测评
- Kubernetes 深入理解Kubernetes(二) 声明组织对象
- Oracle 云基础设施扩展分布式云服务,为组织提供更高的灵活性和可控性
- 设计人工智能产品:技术可能性、用户合意性、商业可行性
- 黑苹果安装教程OC引导「建议收藏」
- From PDB source code to frame frame object
- Pytorch model
猜你喜欢

PostgreSQL超越MySQL

DevEco Studio 3.0编辑器配置技巧篇

Mobile web training day-2

Mobile web training -flex layout test question 1

StackOverflow 2022数据库年度调查

Oracle 云基础设施扩展分布式云服务,为组织提供更高的灵活性和可控性

如何设计数据可视化平台

1015. picking flowers

The company leader said that if the personal code exceeds 10 bugs, he will be dismissed. What is the experience?

Votre Code parle? (1)
随机推荐
欧拉恒等式:数学史上的真正完美公式!
Idea global search shortcut settings
From PDB source code to frame frame object
Inftnews | technology giants accelerate their march into Web3 and metauniverse
Mobile web training day-1
Operation and maintenance thinking | do you know the relationship between CMDB and monitoring?
PHP gets the number of digits and replaces it with the specified mantissa
PHP obtains the beginning and end time of the month according to the month and year
几百行代码实现一个 JSON 解析器
My hematemesis collection integrates script teaching from various classic shell books. As Xiaobai, come quickly
Summary of 2021 computer level III database
Class structure in C language - dot
Recognize the startup function and find the user entry
Votre Code parle? (1)
Is it safe for Huatai Securities to open an account? Is there any risk in opening an account
众昂矿业着眼氟化工产业,布局新能源产业链
接雨水系列问题
Oracle cloud infrastructure extends distributed cloud services to provide organizations with greater flexibility and controllability
How fragrant! The most complete list of common shortcut keys for pychar!
PCB understand Wang, are you? I am not