JDK集合框架--ArrayList
ArrayList,从类名就可以看出来,这是由数组实现的List,即内部是用数组保存元素的有序集合。先看看主要的成员变量,比较简单:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* 默认的初始数组大小
*/
private static final int DEFAULT_CAPACITY = 10;/**
*用于储存具体元素的数组对象
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
*
*数组中元素的数量
*/
private int size;
三个构造函数:
/**
*
* 创建一个确定初始大小的数组
* @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);
}
} /**
* 不创建数组,使用默认的空数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
*传入一个Collection 的实现类 并转换成Object[]数组*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)->有些集合的toArray方法返回的对象类型可能不是Object[].class
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 使用空数组作为初始数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
如果可以大体上确定ArrayList需要所元素的数量,尽量使用ArrayList(int initialCapacity)指定初始容量,可以有效避免其扩容次数(多数底层使用数组实现的集合有相同的特点)
接下来分析其扩容机制,先看看add(E e)方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); //判断是否需要扩容
elementData[size++] = e;//添加对象引用
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//即使用的是无参构造器创建对象,且是第一次添加元素的情况
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果当前所需最小容量小于默认值10,则最小值作为当前容量
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果当前所需的容量超出,之前数组大小 则进行扩容操作
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//核心扩容方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//原来数组的1.5倍
//新数组的大小必须至少为原数组大小的1.5倍,否则直接扩容为1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//新的数组长度如大于默认最大的数组长度MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 创建数组,将旧数组中的数据复制到新数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//所需最小的数组大小如果大于MAX_ARRAY_SIZE,则直接取int类型最大值,反之,取默认最大值MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
所有的添加操作都是需要调用ensureCapacityInternal方法,判断是否需要,并进行扩容操作
这里总结一下:
ArrayList默认容量是10,如果初始化时一开始指定了容量,或者通过集合作为元素,则容量为指定的大小或参数集合的大小。每次扩容为原来的1.5倍,如果新增后超过这个容量,则容量为新增后所需的最小容量。如果增加0.5倍后的新容量超过限制的容量,则用所需的最小容量与限制的容量进行判断,超过则指定为Integer的最大值,否则指定为限制容量大小。然后通过数组的复制将原数据复制到一个更大(新的容量大小)的数组。
再看看ArrayList中其他动态的方法:
//根据索引移除
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;
}
//移除所有元素
public void clear() {
modCount++; // clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
}
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++;
}
所有的移除工作都是找到对应的数组下标项,然后置空,具体的对象回收是jvm的工作;进行删除和插入操作时,为了维持数组中元素的连续性,则需要调用System.arraycopy(),重新并排数组元素,时间复杂度是线性的,效率很低,所以ArrayList不适合需要经常对集合进行动态操作的场景。
最后看看ArrayList访问元素的方法:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
很简单,就是利用数组的索引访问,常数时间复杂度,效率很高,所以对于频繁读取的场景,使用ArrayList再好不过了
JDK集合框架--ArrayList的更多相关文章
- JDK(一)JDK集合框架
JDK中的集合框架分为两大类:Collection和Map.Collection以一组Object的形式保存元素,Map以Key-Value对的形式保存元素. 上图列出的类并不完整,只列举了平时比较常 ...
- 集合框架-ArrayList,Vector,Linkedlist
// ClassCastException 报错,注意,千万要搞清楚类型 * Vector的特有功能: * 1:添加功能 * public void addElement(Object obj) -- ...
- Java基础-集合框架-ArrayList源码分析
一.JDK中ArrayList是如何实现的 1.先看下ArrayList从上而下的层次图: 说明: 从图中可以看出,ArrayList只是最下层的实现类,集合的规则和扩展都是AbstractList. ...
- 大数据学习笔记——Java篇之集合框架(ArrayList)
Java集合框架学习笔记 1. Java集合框架中各接口或子类的继承以及实现关系图: 2. 数组和集合类的区别整理: 数组: 1. 长度是固定的 2. 既可以存放基本数据类型又可以存放引用数据类型 3 ...
- JDK集合框架源码分析 - 简单概要
1.类继承体系 在集合框架的类继承体系中,最顶层有两个接口Collection.Map: Collection 表示一组纯数据 Map 表示一组key-value对 Collection的类继承体系: ...
- JAVA基础--JAVA API集合框架(ArrayList、HashSet、HashMap使用)14
一.集合Collection 1. 集合介绍 变量:表示的内存中的一个空间,只能保存确定类型的单个数据 数组:表示的是内存中的多个连续的空间,这些空间中可以存储多个同类型的数据. 后期继续学习面向对象 ...
- JDK集合框架--综述
接下来的几篇博客总结一下对jdk中常用集合类知识,本篇博客先整体性地介绍一下集合及其主要的api: 从整体上来说,集合分两大类collection和map: 首先来看看Collection: c ...
- 集合框架,ArrayList和Vector的区别,让arrayList线程安全的几种方案
boolean add(E e) 将指定的元素添加到此列表的尾部. void add(int index, E element) 将指定的元素插入此列表中的指定位置. boolean addAll(C ...
- 集合框架 ArrayList LinkedList(待续)
ArrayList中存储的元素的内存空间是连续的, LinkedList内存空间不是连续的 集合对象不能被序列化到硬盘中 http://blog.csdn.net/eson_15/article/de ...
随机推荐
- LoadRunner---http请求中对中文参数的处理
Loadrunner 做保险承保业务测试 1. 保险正常业务流程:保费计算--->保存--->申请核保--->核保--->缴费(出保单) 问题一描述 保费计算接口中,需要把车牌 ...
- JavaSE入门学习23:Java面向对象之构造方法
学了JavaSE面向对象这一部分,也该对构造方法做一个总结了. 一构造方法 在多数情况下,初始化一个对象的终于步骤是去调用这个对象的构造方法. 构造方法负责对象的初始化工作,为 实例变量赋予合适的初始 ...
- 10 逻辑完善以及bug修复
进行到这里,我们应用开发已经接近尾声,我这里基本就是应用开发的记录过程,讲解的东西很少,有问题可以在评论区讨论呦.下面进入最后调整的阶段. 预览我们的应用,会发现首页的职位列表,也会显示收藏的星星图标 ...
- Node-webkit 介绍
什么是Node-webkit ? Node-webkit 是Intelproject师rogerwang写的一个基于node.js和chromium的应用程序执行环境,通过node-webkit,我们 ...
- ASP.NET for WebApi
WebApi,听说过吧?呵呵. 感觉比WebService,WCF要强.尤其是那个啥WCF,啥鬼东西,真难懂.真难搞.真难用. 说比WebService要强,是因为不用在本地先生成个代理.而且XML也 ...
- 设备没有可用空间 /var/spool/clientmqueue sendmail
[root@hadoop3 /]# crontab -e/tmp/crontab.TB7A7w: 设备上没有空间[root@hadoop3 /]# df -Bg文件系统 1G-块 已用 可用 已用% ...
- Cron Expression
CronTrigger CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表.CronTr ...
- Codeforces Round #261 (Div. 2)——Pashmak and Graph
题目链接 题意: n个点.m个边的有向图.每条边有一个权值,求一条最长的路径,使得路径上边值严格递增.输出路径长度 )) 分析: 由于路径上会有反复点,而边不会反复.所以最開始想的是以边为状态进行DP ...
- 解决Android 6.0获取wifi Mac地址为02:00:00:00:00:00问题【转】
本文转载自:http://www.jb51.net/article/128398.htm 这篇文章主要介绍了Android 6.0获取wifi Mac地址为02:00:00:00:00:00的解决方法 ...
- 一步一步学Silverlight 2系列(2):基本控件
述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...