基于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 ...
随机推荐
- django 编程小结
1.增删改查 add obj = Obj(atr=atr..) obj.save() update: __dict__ 遍历 del: 根据id列表删除 query: 首次查询: 直接跳转至页面,前端 ...
- 在windows64位Anaconda3环境下安装XGBoost
安装步骤参考的是: "Installing XGBoost For Anaconda on Windows":https://www.ibm.com/developerworks/ ...
- Java 调用python说明文档
Java 调用python说明文档 通过java调用python脚本主要如下三种方式: 1.直接执行python脚本: 2.执行python.py文件: 3.使用Runtime.getRuntime( ...
- linux_文件类型
linux中文件类型? 在linux系统中一切(目录.普通文件.设备文件等)皆文件 d 目录 - 普通文件 l 链接文件 b 快设备和其他外网设备 普通文件: - ...
- Java 生产者消费者模式详细分析
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- 【转】用Linux命令行获取本机外网IP地址
$ curl ifconfig.me $ curl icanhazip.com $ curl ident.me $ curl ipecho.net/plain $ curl whatismyip.ak ...
- 一个最简单的cell按钮点击回调
在cell.h定义 @property(nonatomic,strong)void(^pushType)(NSInteger); 在cell.m按钮点击时 _pushType(1):(举例) ...
- 面向对象_06【抽象类:abstract、接口:interface、实现:implements】
抽象类:abstract抽象:没有足够的描述功能,事物不具体的描述,却又有共性. 特点: 1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰,抽象方法必须定义在抽象类中,该类也 ...
- 面试中的Https
在Http协议中有可能存在信息窃听或身份伪装的安全问题.使用HTTPS通信机制可以有效地防止这些问题. Https Http的缺点 通信使用明文(不加密),内容可能会被窃听. 不验证通信方的身份,因此 ...
- PHP实现html字符实体转汉字
就一个函数搞定了: mb_convert_encoding("人人", "UTF-8", "HTML-ENTITIES"); 这个函数原本是 ...