【集合框架】JDK1.8源码分析之ArrayList详解(一)
【集合框架】JDK1.8源码分析之ArrayList详解(一)
一. 从ArrayList字表面推测
ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,List的中文意思是列表。从ArrayList字表面推测,ArrayList类是否有数组和列表的特征?那么,这些特征这在ArrayList类中又是怎么体现的?
ArrayList源码分析
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
从上面的代码可知道,以下几点
- 继承了AbstractList类,实现了List,意味着ArrayList是一个数组队列,提供了诸如增删改查、遍历等功能。
- 实现了RandomAccess接口,意味着ArrayList提供了随机访问的功能。RandomAccess接口在Java中是用来被List实现,用 来提供快速访问功能的。在ArrayList中,即我们可以通过元素的序号快速获取元素对象。
- 实现了Cloneable接口,意味着ArrayList实现了clone()函数,能被克隆。
实现了java.io.Serializable接口,意味着ArrayList能够通过序列化进行传输。
ArrayList的属性
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 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 = {};
/**
* 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 Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
- DEFAULT_CAPACITY :默认容量大小为10。
- EMPTY_ELEMENTDATA :用于Constructs有参数传入,如果参数等于零,则使用该属性。
- DEFAULTCAPACITY_EMPTY_ELEMENTDATA :用于Constructs无参数传入默认大小为10(具体运用于add中),使用使用该属性。
- size :当前容量大小
## 构造分析
### 有参数构造Method
传入initialCapacity参数,如果参数大于零,创建一个大小为initialCapacity的数组
/** * 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) { //new一个大小为initialCapacity的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
无参数构造Method
里面只有一个操作就是把 elementData
设置为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
这个空数组。
// 无参的构造函数,传入一个空数组 这时候会创建一个大小为10的数组,具体操作在 add 中
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
增删查改Method
add Method
这个方法首先调用了 ensureCapacityInternal()
这个方法里面就判断了当前的 elementData
是否等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
如果是的话,就把数组的大小设置为 10 然后进行扩容操作,这里刚好解释了为什么采用无参构造的List 的大小是 10 ,这里扩容操作调用的方法是 ensureExplicitCapacity
里面就干了一件事如果用户指定的大小 大于当前长度就扩容,扩容的方法采用了 Arrays.copy
方法,这个方法实现原理是 new 出一个新的数组,然后调用 System.arraycopy
拷贝数组,最后返回新的数组。
public boolean add(E e) {
// 当调用了无参构造,设置大小为10
ensureCapacityInternal(size + 1); // Increments modCount
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 如果当前数组是默认空数组就设置为 10和 size+1中的最小值
// 这也就是说为什么说无参构造 new 的数组大小是 10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 若用户指定的最小容量 > 最小扩充容量,则以用户指定的为准,否则还是 10
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:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Remove Method
通过index知道位置,然后index位置的值被index+1位置的值往前覆盖,覆盖的次数为size - index - 1
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
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;
}
get Method
通过index 来访问元素
public E get(int index) {
//检测范围
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
}
set Method
通过index知道要修改的元素并替换了
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
【集合框架】JDK1.8源码分析之ArrayList详解(一)的更多相关文章
- nginx源码分析线程池详解
nginx源码分析线程池详解 一.前言 nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...
- 【集合框架】JDK1.8源码分析之ArrayList(六)
一.前言 分析了Map中主要的类之后,下面我们来分析Collection下面几种常见的类,如ArrayList.LinkedList.HashSet.TreeSet等.下面通过JDK源码来一起分析Ar ...
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- vuex 源码分析(五) action 详解
action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...
- Golang源码分析之目录详解
开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...
- Java 容器源码分析之集合类详解
集合类说明及区别 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └W ...
- Tomcat源码分析 | 一文详解生命周期机制Lifecycle
目录 什么是Lifecycle? Lifecycle方法 LifecycleBase 增加.删除和获取监听器 init() start() stop() destroy() 模板方法 总结 前言 To ...
- Cloudera Impala源码分析: SimpleScheduler调度策略详解包括作用、接口及实现等
问题导读:1.Scheduler任务中Distributed Plan.Scan Range是什么?2.Scheduler基本接口有哪些?3.QuerySchedule这个类如何理解?4.Simple ...
- 【集合框架】JDK1.8源码分析之HashMap(一) 转载
[集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...
随机推荐
- Server Error in '/' Application Runtime Error 错误
项目发布后 在本地发布可以运行 在服务器就会出现这种错误 在网上也查找了各种资料 解决方案 都没有解决 因为我用的C# 首先在 Webconfig配置文件中的 system.web中加入 < ...
- 第9章 设备授权端点(Device Authorization Endpoint) - IdentityModel 中文文档(v1.0.0)
OAuth 2.0设备流设备授权的客户端库是作为HttpClient扩展方法提供的. 以下代码发送设备授权请求: var client = new HttpClient(); var response ...
- 贾天昊 - Nick
- 基于geoserver的REST服务完成mysql数据源动态发布
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 在之前的<简析GeoServer服务的内部文件组织以及 ...
- 运维DBA要不要学python
运维DBA要不要学python 我个人认为是:要 现在python在运维数据库的工作中主要用在 1.编写一些运维脚本 2.编写运维管理平台 3.研究互联网大厂的运维脚本/工具并应有 特别是运维开源数据 ...
- 解决mysql中只能通过localhost访问不能通过ip访问的问题
解决mysql中只能通过localhost访问不能通过ip访问的问题 原因是没开权限 SELECT * FROM USER WHERE USER='root'; grant all privilege ...
- windows之如何把文件夹转换成iso文件
(1)oscdimg下载路径: 链接:https://pan.baidu.com/s/1U_SfamsOvI2nav9odAzujQ提取码:21fr (2)以管理员身份运行cmd命令: Oscdimg ...
- redis缓存类
<?php class Redis_model{ public $redis = null; public function __construct() { $hosts = $this-> ...
- 分布式锁实现秒杀 - 基于redis实现
业务场景 所谓秒杀,从业务角度看,是短时间内多个用户“争抢”资源,这里的资源在大部分秒杀场景里是商品:将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢, ...
- 多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport
◆CountDownLatch◆ 假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以.比如你想要买套房子,但是呢你现在手上没有钱.你得等这个月工资发了.然后年终奖发了.然后朋友借你得钱 ...