基于JDK1.8的ArrayList剖析
前言
本文是基于JDK1.8的ArrayList进行分析的。本文大概从以下几个方面来分析ArrayList这个数据结构
- 构造方法
- add方法
- 扩容
- remove方法
(一)构造方法
/**
* 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) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
} /**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
总所周知,ArrayList底层是数组
我们先看第二个构造方法,即无参构造方法(第22行),将默认空数组赋值给Object数组。这一段执行完,就在堆中分配了一段空的数组。
我们再看第一个构造方法,有参构造方法。
/**
* 加入我们有这么一段代码
*/
List<String> list = new ArrayList<>(10);
其构造方法有三个分支,initialCapacity大于0,等于0,小于0。我们直接看大于0,其他两个看代码就懂了。
他会直接构造一个以initialCapacity为大小的Object数组。
(二)add方法
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
size这个字段为数组的长度。然后进入ensureCapacityInternal这个方法。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}
可以看出来,第二行是判断是否位第一次add,也就是初始化。如果数组位空,那么DEFAULT_CAPACITY就是为10。
初始化完成,也就是开辟一个大小为10的Object数组。
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
minCapacity是list里面元素的个数,比如第一次放,也就是10,elementData.length也就是数组的长度,也就是0。
那么减法结果就为 10,不成立就不扩容,如果成立就扩容。
elementData[size++] = e;
然后返回add方法,执行这一句,至此,add方法就执行完毕了.接下来我们看下扩容的代码。
(三)扩容
/**
* 我们假设第一次扩容,list数组容量为10,再次add那么传过来的minCapacity为11
* oldCapacity为10
* newCapacity为 10 + (10 / 2) = 15 也就是扩容1.5倍
* 有两个if的极值判断,看代码很简单就懂了
* 然后执行Arrays.copy方法
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
我看了下Arryas的copy方法,也不难,大家可以对照着源码自己去看一下。
至此ArrayList的add方法就介绍完了,grow方法也搞定了。
(四)remove方法
/**
* remove方法总共有两个,一个是按照index删除,一个是按照元素删除,大同小异
* 下面说按照index删除,看注释
*/
public E remove(int index) {
//首先检查是否越界
rangeCheck(index); modCount++;
E oldValue = elementData(index); int numMoved = size - index - 1;
//把后面的全部移到前面一位,System.arraycopy是一个native方法
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//然后最后一位置为空值,gc会自动回收
elementData[--size] = null; // clear to let GC do its work return oldValue;
}
remove方法很简单,直接看我写的注释即可。
(五)总结
写了两个多小时,我也醉了。主要我在调试eclipse的debug,我的那个有点问题,eclipseEE版本就没有问题。
其实我有一点疑惑,希望大佬能够给我解答以下。
初始化构造方法那里,并没有给size赋值,也就是为null值,不能直接输出或者使用(会报错,已实验)
但调用list.size()方法的时候,返回的确是0,没有报错,我debug也没看出来什么时候赋值了。
大佬看到这篇文章,希望可以解答下。谢谢。
-------------------------------华丽分割线----------------------------
好累啊
基于JDK1.8的ArrayList剖析的更多相关文章
- Java集合(四)--基于JDK1.8的ArrayList源码解读
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...
- Java集合基于JDK1.8的ArrayList源码分析
本篇分析ArrayList的源码,在分析之前先跟大家谈一谈数组.数组可能是我们最早接触到的数据结构之一,它是在内存中划分出一块连续的地址空间用来进行元素的存储,由于它直接操作内存,所以数组的性能要比集 ...
- ConcurrentHashMap基于JDK1.8源码剖析
前言 声明,本文用的是jdk1.8 前面章节回顾: Collection总览 List集合就这么简单[源码剖析] Map集合.散列表.红黑树介绍 HashMap就是这么简单[源码剖析] LinkedH ...
- 基于JDK1.8的LinkedList剖析
之前写了一篇ArrayList,那么今天就写一篇他的姊妹篇,LinkedList. 众所周知,ArrayList底层数据是数组,可以在O(1)的时间内get到数据,但删除和插入就要O(n)时间复杂度. ...
- 基于jdk1.8的ArrayList源码分析
前言ArrayList作为一个常用的集合类,这次我们简单的根据源码来看看AarryList是如何使用的. ArrayList拥有的成员变量 public class ArrayList<E> ...
- Java -- 基于JDK1.8的ArrayList源码分析
1,前言 很久没有写博客了,很想念大家,18年都快过完了,才开始写第一篇,争取后面每周写点,权当是记录,因为最近在看JDK的Collection,而且ArrayList源码这一块也经常被面试官问道,所 ...
- ArrayList的实现细节(基于JDK1.8)
ArrayList是我们经常用到的一个类,下面总结一下它内部的实现细节和使用时要注意的地方. 基本概念 ArrayList在数据结构的层面上讲,是一个用数组实现的list,从应用层面上讲,就是一个容量 ...
- Java集合类源码解析:HashMap (基于JDK1.8)
目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...
- 基于JDK1.8的LinkedList源码学习笔记
LinkedList作为一种常用的List,是除了ArrayList之外最有用的List.其同样实现了List接口,但是除此之外它同样实现了Deque接口,而Deque是一个双端队列接口,其继承自Qu ...
随机推荐
- 新装Centos7.2 配置防火墙
1.安装 yum -y install firewalld2.开机启动 systemctl enable firewalld3.设置防火墙规则 systemctl restart firewalld ...
- webpack 基本打包方法
webpack的打包基本配置文件webpack.config.js 可以在webpack.config.js里面写好配置:比如前章节所总结的四大核心 |-- add.js // 定义一个普通加法函数 ...
- mysql根据汉字首字母排序[转]
select areaName from area order by convert(areaName USING gbk) COLLATE gbk_chinese_ci asc 说明 ...
- arduino笔记
接下来,初来博客,准备自己也写一系列的arduino的学习经验. http://zhongbest.com/2017/05/23/arduino%e4%b8%ad%e7%9a%84%e4%b8%ad% ...
- Azure VM 防止被入侵
伴随着开源Linux系统的逐渐盛行,在机器上线之前配置好安全策略至关重要,分享几点有关Azure Linux VM机器的安全建议如下: 1.禁止root账号登录虚拟机,并增加密码的复杂度(大小写字母, ...
- 云计算之路-阿里云上:部分服务器未及时续费造成docker swarm集群故障
非常非常抱歉,由于我们的疏忽 —— docker swarm 集群中的 2 台服务器没有及时续费,造成在夜里0点被自动关机,从而引发整个 docker swarm 集群故障,造成今天凌晨 0:30 ~ ...
- linux中操作java进程
通过 ps -ef|grep java 来得到真正运行的线程 通过kill -9 XXXXX来杀死正在运行的线程,其中XXXXX是上面java线程的序号. 另外还有2个指令我也不熟悉,一个是cat,一 ...
- HSSF、XSSF和SXSSF区别以及Excel导出优化
之前有写过运用POI的HSSF方式导出数据到Excel(见:springMVC中使用POI方式导出excel至客户端.服务器实例),但这种方式当数据量大到一定程度时容易出现内存溢出等问题. 首先,PO ...
- 豹哥嵌入式讲堂:ARM知识概要杂辑(4)- Cortex-M处理器性能指标
1.处理器的性能指标 用于评价CPU的性能指标非常多,不同的性能侧重点下的测试标准可能得出的指标值不同,下面介绍嵌入式行业广泛使用的两个经典的测试标准. 1.1 Dhrystone标准 Dhrysto ...
- OpenFlow交换机的实现总结
先粗略介绍,后续会逐渐完善. OpenFlow交换机通过使用OpenFlow协议的安全通道与控制器进行通信.其具体实现如下示意图所示: 对于一个新到达的数据流,交换机通常的做法是,把该数据包发送给控制 ...