ArrayList源码详解
时间:2019-02-19
本文章向大家介绍ArrayList源码详解,主要包括ArrayList源码详解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
ArrayList
1特点
适合做查找;不适合做删除和插入,这样会复制,移动元素;
查找O(1),删除和插入为O(n)
默认构造器
无参数初始空数组,new时,数组大小仍然为空,一旦添加就扩容变成10;
private static final Object[] EMPTY_ELEMENTDATA = {};
<!--与上面都是空数组,但是带大小的构造器初始化时,会使让该数组变成该大小,之后不再改变。最后通过比较element的大小来知道数组变大了多少。-->
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
<!--真正被操控的数组-->
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
指定大小有参数构造
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);
}
}
将集合作为参数传入构造器
public ArrayList(Collection<? extends E> c) {
<!--element最后的类型可能不是c的类型数组而是c的子类,由于java运行时多态的原因,此时再element添加一个c类型的元素就会报错java.lang.ArrayStoreException-->
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
<!--为了避免上述原因,需要重新转化-->
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
末尾直接添加
public boolean add(E e) {
//确保容量够用
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
rivate void ensureCapacityInternal(int minCapacity) {
//第一添加时,初始化数组大小,如果初始化大小《10 (默认大小),直接使用默认大小。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
<!--确保size不会因为二进制加法溢出变成负数-->
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 添加一个元素后使得,元素个数超过了数组的大小就扩容
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);
}
指定位置添加
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size++;
}
将一个集合全部添加到一个list里面
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
从指定位置添加一个集合
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
删除
删除指定索引,数组整体前移。
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;
}
删除指定对象
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
<!--被移动的个数-->
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
}
查找
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
迭代
边遍历边删除元素时,最好使用迭代器模式,不会出问题
,使用for循环会出现ConcurrentModificationException;
ArrayList<Integer> integers1 = new ArrayList<>();
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()) {
if (iterator.next() == 1) {
iterator.remove();
}
}
- 深入浅出Redis-redis哨兵集群
- Spring-Blog:个人博客(一)-Mybatis 读写分离
- Spring-boot:5分钟整合Dubbo构建分布式服务
- MYSQL5.6优化器的一个新特性MMR
- Mysql聚集索引和非聚集索引
- Spring-Boot:6分钟掌握SpringBoot开发
- Zookeeper-5分钟快速掌握分布式应用程序协调服
- Mysql索引长度计算
- Spring-Boot:Spring Cloud构建微服务架构
- Python-WXPY实现微信监控报警
- MySQL InnoDB Lock(一)
- Java 时间类-Calendar、Date、LocalDate/LocalTime
- Java消息队列--JMS概述
- Java FtpClient 实现文件上传服务
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- C# 获取txt文件邮箱号码并去重复
- C#中Enum用法小结
- Python爬虫基础总结
- C# TASK使用实例
- [打造自己的监控系统之执行Oracle命令]获取Oracle执行次数等于一的语句(硬解析状况)
- [打造自己的监控系统之执行Oracle命令]检查未绑定变量的语句(硬解析状况)
- httpclient使用HTTP代理实践
- 使用Python利用微信企业号发送报警信息
- C# Task.Delay() 和 Thread.Sleep() 区别
- Csharp实例:武汉智能安检闸机数据接收和解析
- [周末往期回顾]Oracle基本参数(LOG_ARCHIVE_DEST_n)
- [周末往期回顾]Oracle基本参数(SGA_TARGET)
- C#如何释放已经加载的图片
- 笔记本内置摄像头视频播放和存储
- [Data Guard全解析]5.Data Guard及ADG日常运维操作