Java源码系列1——ArrayList
本文简单介绍了 ArrayList
,并对扩容,添加,删除操作的源代码做分析。能力有限,欢迎指正。
ArrayList是什么?
ArrayList
就是数组列表,主要用来装载数据。底层实现是数组 Object[] elementData
,当我们装载的是基本数据类型 int, long, boolean, shot...的时候我们只能存储他们对应的包装类型。
与它类似的是 LinkedList
,和 LinkedList
相比,它的查找和访问元素的速度较快,但新增,删除的速度较慢。
线程安全吗?
线程不安全。
正常使用场景中,ArrayList
都是用来查询,不会涉及太频繁的增删,如果涉及频繁的增删,可以使用 LinkedList
。如果需要线程安全就使用 Vector
。
Vector
是 ArrayList
的线程安全版本,实现方式就是在所有方法加上synchronized
,性能较差。
如何扩容?
因为数组的大小是固定,当容量超出了现有数组的大小,就需要进行扩容。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 每次扩大原有容量的一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩大一半后还是无法满足,则使用minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果超过最大size,则获取最大容量的数组
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);
}
为什么说ArrayList插入效率低?
原因有两点:
- 新增就要检测容量够不够,如果不够就需要扩容
- 尾部新增比较快,如果是在数组头部或者中部新增就会慢很多,因为要把后面的元素全部往后移一位
- 把元素往后移一位使用的是复制
System.arraycopy()
,它是native
方法(java定义了接口,其他语言进行实现),所以比较快
/**
* 添加在尾部
*/
public boolean add(E e) {
// 检查容量
ensureCapacityInternal(size + 1);
// 添加在尾部
elementData[size++] = e;
return true;
}
/**
* 按指定位置添加
*/
public void add(int index, E element) {
// 检查index
rangeCheckForAdd(index);
// 检查容量
ensureCapacityInternal(size + 1);
// index后面的元素全部往后移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
删除元素效率如何?
效率和新增差不多,都是要移动元素,但是不需要检查容量和扩容。
public E remove(int index) {
// 检查index
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
// index后面的元素全部往前移一位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
适合做队列吗?
非常不适合。
队列是FIFO,在尾巴进,头部出,出的时候需要移动后面所有数据,效率很低。链表比较适合做队列。
new ArrayList<>(18) 会不会初始化数组大小?
不会初始化数组大小!!!
这是Java Bug。
而且将构造函数与initialCapcity结合使用,然后使用set()方法会抛出异常。
public static void main(String[] args) {
ArrayList<Integer> a = new ArrayList<>(12);
System.out.println(a.size());
a.set(3, 3);
}
总结
- 底层实现是数组
Object[] elementData
- 查找和访问元素的速度较快,但新增,删除的速度较慢
- 线程不安全
- 每次扩容原有数组大小的一半
源码系列文章
本文首发于我的个人博客 http://chaohang.top
作者张小超
转载请注明出处
欢迎关注我的微信公众号 【超超不会飞】,获取第一时间的更新。
Java源码系列1——ArrayList的更多相关文章
- Java源码系列2——HashMap
HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...
- Java源码阅读之ArrayList
基于jdk1.8的ArrayList源码分析. 实现List接口最常见的大概就四种,ArrayList, LinkedList, Vector, Stack实现,今天就着重看一下ArrayList的源 ...
- 【java集合框架源码剖析系列】java源码剖析之ArrayList
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...
- 【Java源码】集合类-ArrayList
一.类继承关系 public class ArrayList<E> extends AbstractList<E> implements List<E>, Rand ...
- Java源码分析之ArrayList
ArrayList是以数组为基准的容器类,和LinkedList(链表)正好相反.因而ArrayList拥有更好的查找性能,增删操作则差一些.ArrayList封装了对于常规数组的操作,同时可以自动扩 ...
- Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
我们知道 HashMap 的底层是由数组,链表,红黑树组成的,在 HashMap 做扩容操作时,除了把数组容量扩大为原来的两倍外,还会对所有元素重新计算 hash 值,因为长度扩大以后,hash值也随 ...
- java源码之集合类ArrayList
1. ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部 ...
- java基础解析系列(十)---ArrayList和LinkedList源码及使用分析
java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...
- 深入学习JDK源码系列之、ArrayList
前言 JDK源码解析系列文章,都是基于JDK8分析的,虽然JDK15马上要出来了,但是JDK8我还不会,我... 类图 实现了RandomAccess接口,可以随机访问 实现了Cloneable接口, ...
随机推荐
- SpringCloud之Feign(五)
Feign简介 Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Fei ...
- Mysql连接出现时区问题
错误提示: The server time zone value '¥x¥_¼Ð·Ç®É¶¡' is unrecognized or represents more than one time zon ...
- 跨源请求cors和jsonp
0.产生跨域的原因 浏览器的同源策略 什么是浏览器的同源策略? src开发 ajax禁止 解决方法 jsonp 通过src绕过浏览器的同源策略 缺点:只发送GET请求 cors 通过设置相应头 分类 ...
- 多级反向代理java获取真实IP地址
public static String getIpAddress(HttpServletRequest request){ String ip = request.getHeader("x ...
- Mysql 8+ 版本完全踩坑记录
问题是这样 刚霍霍了一台腾讯云服务器需要安装mysql 然后就选择了8+这个版本. 安装步骤网上有的是. 我只写最主要的部分 绝对不出错 外网可访问 .net java都可以调用 其实不指望有人看 就 ...
- 关于SOA架构设计的案例分析
关于SOA架构设计的案例分析 面向服务的体系结构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.它可以根据需求通过网络对松散耦合的粗粒度应 ...
- Dynamics 365 CRM 在 Connected Field Service 中部署 IoT Central (三)- 发送 work order 和 booking 信息给 IoT Central
首先, 我们可以打开IoT alert, 并且点击上的 create a flow. 接下来,我们使用微软准备好的模板:Sample Contoso- When a work order is cre ...
- FileUpload实现图片的无重上传
//如果确认了上传文件,则判断文件类型是否符合要求 if (this.FileUpload1.HasFile) { //获取上传文件的后缀 ...
- 解决keil5不支持Samsung 2440A等较旧型号Soc的方法
手上有一块mini2440,最近想拿来跑一下程序.于是去下了最新版的Keil5,结果发现创建工程时没有Samsung一系列型号的CPU选项. 没有办法,去网上找了很久,才发现原因是新版的Keil5 ...
- spring源码系列(一):使用Gradle构建spring5源码的一些坑和步骤
源代码github: https://github.com/spring-projects/spring-framework.git 一 修改项目配置文件中gradle版本和地址 替换成本地安装的版 ...