ArrayList源码解读
在端午节这个节日里,有一个特殊的任务,我带着你一起揭开“ArrayList”的真面目。从成员变量、构造函数、主要方法三部分,对ArrayList有进一步的认识,希望能够帮助你。
一、成员变量
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//空数组,当调用无参数构造函数的时候默认给个空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//真正保存数据的数组
private transient Object[] elementData;
//数组的大小
private int size;
transient关键字:ArrayList实现了Serializable接口,而添加上transient关键字,则elementData对象就不可以序列化。
二、构造函数
无参构造方法
带有容量的构造方法
带参数Collection的构造方法
在参数Collection的构造方法中,只有当当得到的elementData的类名不是Object,才会执行复制操作,因为Java是动态绑定,所以getClass获取的并不一定是Object类型,有可能是它的子类。
/**
* 初始化elementData
* @param initialCapacity
*/
public ArrayList(int initialCapacity) {
super();
//如果小于0,则抛出异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//初始化elementData数组
this.elementData = new Object[initialCapacity];
} /**
* 初始化为空的对象数组
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
} public ArrayList(Collection<? extends E> c) {
//将c容器转换为object类型的数组
elementData = c.toArray();
//更新size的大小
size = elementData.length;
//当得到的elementData的类名不是Object,才会执行复制操作
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
三、主要方法
1、add方法
//添加元素
public boolean add(E e) {
//首先判断数组容量是否需要扩充
ensureCapacityInternal(size + 1); // Increments modCount!!
//添加元素,更新size的大小
elementData[size++] = e;
return true;
}
ArrayList相当于在没指定initialCapacity时就是会使用延迟分配对象数组空间,当第一次插入元素时ensureCapacityInternal,才分配10个对象空间。
2、get方法
//通过下标获取元素
public E get(int index) {
//判断下标的合理性
rangeCheck(index);
//返回元素
return elementData(index);
}
3、remove方法
在remove方法中,我们需要注意对null的特殊处理。
public boolean remove(Object o) {
//如果为null对象,则特殊处理,使用==来判断
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//如果不为null,则使用equals方法来判断。
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
四、其他常用的方法
removeAll:移除集合A和集合B的交集,即A-B。
retainAll:保留两个集合的交集。
五、ArrayList的大小是如何自动增加的?(面试题)
ensureCapacityInternal 是判断是否要扩容的方法
ensureExplicitCapacity
grow 具体的扩容方法
实现思想:
确定所需minCapacity和数组当前size的关系,如果minCapacity>size,则准备grow。
如果1.5size<minCapacity,则准备扩充为minCapacity。
minCapacity和MAX_ARRAY_SIZE 的关系,如果minCapacity>MAX_ARRAY_SIZE ,则需要判断minCapacity是否超出int类型所能表示的最大值。如果超出,则抛出OutOfMemoryError。
//确保数组能够存放的:minCapacity
private void ensureCapacityInternal(int minCapacity) {
//如果elementData是空对象数组,最小容量为minCapacity和DEFAULT_CAPACITY最大值
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//判断是否需要扩容
ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
//增加被改变的次数
modCount++;
// 最小容量大于elementData的长度,则需要扩充
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} //数组的最大上限
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) {
// 数组原来的长度,保存副本
int oldCapacity = elementData.length;
//扩容至原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判断新容量是否够用,如果不够则赋值为minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果newCapacity超过MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
//检查容量的int值是不是已经溢出。
newCapacity = hugeCapacity(minCapacity);
// 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
// 并将elementData的数据复制到新的内存空间
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
欢迎加入Java学习交流群点击:484757838
ArrayList源码解读的更多相关文章
- ArrayList 源码解读
ArrayList 源码解读 基于JDk 1.7.0_80 public class ArrayList<E> extends AbstractList<E> impl ...
- JDK12下的ArrayList源码解读 与 Vector的对比
ArrayList源码阅读. //测试代码实现如下 private static void arrayList() { ArrayList<String> list = new Array ...
- ArrayList源码解读(jdk1.8)
概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...
- 深入理解JAVA集合系列四:ArrayList源码解读
在开始本章内容之前,这里先简单介绍下List的相关内容. List的简单介绍 有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制.用户可以根据元素的整数索引(在列表中的位置) ...
- Java集合ArrayList源码解读
最近在回顾数据结构,想到JDK这样好的代码资源不利用有点可惜,这是第一篇,花了心思.篇幅有点长,希望想看的朋友认真看下去,提出宝贵的意见. :) 内部原理 ArrayList 的3个字段 priva ...
- java集合之ArrayList源码解读
源自:jdk1.8.0_121 ArrayList继承自AbstractList,实现了List.RandomAccess.Cloneable.Serializable. ArrayList内部是通过 ...
- ArrayList源码解读笔记
简介: ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高. 线 ...
- Java集合(四)--基于JDK1.8的ArrayList源码解读
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...
- jdk1.8.0_45源码解读——ArrayList的实现
jdk1.8.0_45源码解读——ArrayList的实现 一.ArrayList概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素. ...
随机推荐
- Linux上常用的文件传输方式以及比较
tp ftp 命令使用文件传输协议(File Transfer Protocol, FTP)在本地主机和远程主机之间或者在两个远程主机之间进行文件传输. FTP 协议允许数据在不同文件系统的主机之间传 ...
- vim粘贴代码问题
vim粘贴代码问题 vim 在使用xshell进行vim操作的时候,经常会直接粘贴一些外部的代码,然后粘贴上之后会出现逐行缩进的情况,之前一直没有去找为啥,并且逐行的给他弄回去. 转自:https:/ ...
- 使用 ItextSharp HTML生成Pdf(C#)
以前生成pdf的时候.因为生成的pdf数据是固定的,所以先做好pdf模板,动态的数据可以先用占位符 生成的时候.找到占位符坐标.把数据填充进去 优点:先做好模板.生成的pdf 表格.文.内容会好看一些 ...
- html 压缩工具 html-minifier
https://github.com/kangax/html-minifier#options-quick-reference 1.参数列表 option Description Default re ...
- GitHub上最受欢迎的iOS开源项目TOP20
AFNetworking 在众多iOS开源项目中,AFNetworking可以称得上是最受开发者欢迎的库项目.AFNetworking是一个轻量级的iOS.Mac OS X网络通信类库,现在是GitH ...
- 安卓Native和H5页面进行交互
安卓Native和H5页面进行交互 1.H5页面调用安卓Native界面 1)通过给webView添加JsInterface,安卓提供接口,让H5来进行调用 a)安卓写一个类,里面的方法需要用通 ...
- Python HTMLTestRunner生成网页自动化测试报告时中文编码报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6
1. 由于使用Python Selenium做网页自动化测试时,有截取网页上的中文信息保存到测试结果中,最终出现编码错误如下: File "D:/PycharmProjects/AutoTe ...
- Hibernate学习--hibernate延迟加载原理(动态代理)
在正式说hibernate延迟加载时,先说说一个比较奇怪的现象吧:hibernate中,在many-to-one时,如果我们设置了延迟加载,会发现我们在eclipse的调试框中查看one对应对象时,它 ...
- 简谈-如何使用Python和R组合完成任务
概述 和那些数据科学比赛不同,在真实的数据科学中,我们可能更多的时间不是在做算法的开发,而是对需求的定义和数据的治理.所以,如何更好的结合现实业务,让数据真正产生价值成了一个更有意义的话题. 数据科学 ...
- O(nlogn)实现LCS与LIS
序: LIS与LCS分别是求一个序列的最长不下降序列序列与两个序列的最长公共子序列. 朴素法都可以以O(n^2)实现. LCS借助LIS实现O(nlogn)的复杂度,而LIS则是通过二分搜索将复杂度从 ...