java集合之ArrayList的实现原理
1. ArrayList概述:
ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元
素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素
前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。
2. ArrayList的实现:
对于ArrayList而言,它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作。下面我们来分析ArrayList的源代码:
- 底层使用数组实现
private transient Object[] elementData;
- 构造方法
可以构造一个默认初始容量为0的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
/**
* Shared empty array instance used for empty instances.
空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
- 增加
//将指定的元素添加到元素的尾部
public boolean add(E e) {
//扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//将指定的元素插入此列表中指定的位置
public void add(int index, E element) {
//如果(index >size || index < 0)抛出IndexOutOfBoundsException
rangeCheckForAdd(index);
//数组长度不足,进行扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//将elementData数组中从index位置开始,长度为size - index 的元素拷贝到,从下面index+1开始新的elementData中
//即将当前位于当前位置的元素及后面的元素向右移动一个位置
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 按照指定collection的迭代器所返回的元素顺序,将该collection中的所有元素添加到此列表的尾部。
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;
}
// 从指定的位置开始,将指定collection中的所有元素插入到此列表中。
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 get(int index) {
rangeCheck(index); return elementData(index);
}
- 删除
//移除指定位置上的元素,返回指定位置上原来的元素
public E remove(int index) {
//数组越界检测
rangeCheck(index); modCount++;
E oldValue = elementData(index);
//移除指定位置上的元素,底层数组copy,数组元素向左移动一个位置
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;
}
//移除第一次出现的指定的元素(ArrayList中允许存放重复元素)
public boolean remove(Object o) {
// 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
// 类似remove(int index),移除列表中指定位置上的元素。
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
- 修改:
//用指定元素修改此列表中指定位置上得元素,并返回以前位于该位置上的元素
1 public E set(int index, E element) {
rangeCheck(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
- 数组的扩容
从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超 出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
//扩容方法
grow(minCapacity);
} /**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
扩容的主要方法
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新的数组容量约等于原有的数组容量的1.5倍,oldCapacity >> 1右移一位,newCapacity = oldCapacity + oldCapacity/2
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);
}
//提供的公有的扩展容量的方法,可以手动增加ArrayList容量,可以减少递增式的再分配的数量
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY; if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
从上述代码中可以看出,数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很 高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免 数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。
java集合之ArrayList的实现原理的更多相关文章
- Java集合:ArrayList的实现原理
Java集合---ArrayList的实现原理 目录: 一. ArrayList概述 二. ArrayList的实现 1) 私有属性 2) 构造方法 3) 元素存储 4) 元素读取 5) 元素删除 ...
- 从源码看Java集合之ArrayList
Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...
- 【源码阅读】Java集合之一 - ArrayList源码深度解读
Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. ---@pdai JDK版本 ...
- Java 集合源代码——ArrayList
(1)可以查看大佬们的 详细源码解析 : 连接地址为 : https://blog.csdn.net/zhumingyuan111/article/details/78884746 (2) Array ...
- 深入java集合学习2-ArrayList的实现原理
ArrayList概述 类概述 ArrayList是List 接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素. 每个 ArrayList 实例都有一个容量(ca ...
- Java集合关于ArrayList
ArrayList实现源码分析 2016-04-11 17:52 by 淮左, 207 阅读, 0 评论, 收藏, 编辑 本文将以以下几个问题来探讨ArrayList的源码实现1.ArrayList的 ...
- Java集合干货——ArrayList源码分析
ArrayList源码分析 前言 在之前的文章中我们提到过ArrayList,ArrayList可以说是每一个学java的人使用最多最熟练的集合了,但是知其然不知其所以然.关于ArrayList的具体 ...
- java集合之ArrayList,TreeSet和HashMap分析
java集合是一个重点和难点,如果我们刻意记住所有的用法与区别则是不太现实的,之前一直在使用相关的集合类,但是没有仔细研究区别,现在来把平时使用比较频繁的一些集合做一下分析和总结,目的就是以后在需要使 ...
- Java集合(六)--ArrayList、LinkedList和Vector对比
在前两篇博客,学习了ArrayList和LinkedList的源码,地址在这: Java集合(五)--LinkedList源码解读 Java集合(四)--基于JDK1.8的ArrayList源码解读 ...
随机推荐
- node.js的学习
require('http') 内置模块 server.js var http = require('http'); function start(){ server = http.createSer ...
- OC开发中运用到的枚举
一 常见枚举的定义: typedef enum { LOGIN_SUCCESS, USER_NAME, USER_PASSWORD, OLD_LAT, OLD_LNG }FIELD_SAVED; ...
- C#语法功能结构
1.File打开指定文件夹或者文件,"\"为转义字符System.Diagnostics.Process.Start(Application.StartupPath + " ...
- xml之XSLT
1.XSLT是什么 XSLT是XSL的子集,XSL是样式表.XSLT的作用:将XML文档转化成HTML,做的是中间转换者. 而主要需要学习的是XSLT(XSLTransformation). 2 ...
- linux free 命令
命 令: free 功能说明:显示内存状态. 语 法: free [-bkmotV][-s <间隔秒数>] 补充说明:free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共 ...
- 使用个推的时候出现Installation error: INSTALL_FAILED_DUPLICATE_PERMISSION
使用个推的时候出现 Installation error: INSTALL_FAILED_DUPLICATE_PERMISSION perm=getui.permissio... 解决办法: 先将手机 ...
- MySQL高可用读写分离方案预研
目前公司有需求做MySQL高可用读写分离,网上搜集了不少方案,都不尽人意,下面是我结合现有组件拼凑的实现方案,亲测已满足要求,希望各位多提建议 :) 一. 网上方案整理(搜集地址不详...) 1 ...
- 心情符号love
写点什么呢,先谢谢心情吧,算是第一个脚印了,想先把之前的一些笔记和心得迁移进来吧,以后每个月都要充实自己的知识.向大婶们看齐.走你们走过的脚印,看你们前行的身影.沿着你们留下的路,继续为后者拓宽道路. ...
- JavaWeb实现文件上传下载功能实例解析
转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...
- hdu 3157 Crazy Circuits 网络流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3157 You’ve just built a circuit board for your new r ...