Java源码系列1——ArrayList
时间:2022-07-25
本文章向大家介绍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
- 查找和访问元素的速度较快,但新增,删除的速度较慢
- 线程不安全
- 每次扩容原有数组大小的一半
作者张小超 转载请注明出处
- mysql密码遗忘和登陆报错问题
- 新一轮发展趋势:城市智能化已经势不可挡
- Enterprise Library 4.1学习笔记2----数据访问程序块
- 微信小程序中用户唯一ID的获取
- Mysql备份系列(2)--mysqldump备份(全量+增量)方案操作记录
- Enterprise Library 4.1学习笔记1----配置应用程序块(c/s和b/s均适用)
- 简单账本-用完即走的微信小程序
- 新技术革命和新产业变革正进行 “互联网+大数据+人工智能+”时代正到来
- 微信小程序开发及相关设置小结
- gitlab两种连接方式:ssh和http配置介绍
- C#实现微信AES-128-CBC加密数据的解密
- UrlReferrer为空的问题?
- DeepMind发文回顾2017:AlphaGo团队已迎战下一个重大挑战
- [你必须知道的.Net]读书笔记--浅clone与深clone
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 安装ubuntu时黑屏的解决办法(3种)
- linux输入yum后提示: -bash: /usr/bin/yum: No such file or directory的解决方法
- 分布式锁,三种实现方式,性能对比分析!
- Linux 中锁定和解锁用户帐户的三种方法
- centos8 安装 nginx的详细教程(图文)
- Ubuntu系统日志配置 /var/log/messages的方法
- 在Ubuntu 14 上安装 Nginx-RTMP 流媒体服务器的教程
- centos8自定义目录安装nginx(教程详解)
- VMware下Centos7桥接方式网络配置步骤详解
- Linux CentOS 6.5 卸载、tar安装MySQL的教程
- Linux CentOS 6.5 ifconfig查询不到ip的解决方法
- 打卡群2刷题总结1009——二叉树的中序遍历
- 解决Ubuntu 18.04安装VMwareTools错误问题
- 对linux下syslogd以及syslog.conf文件的解读说明
- Linux下安装tomcat并部署网站(推荐)