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的更多相关文章

  1. JDK(一)JDK集合框架

    JDK中的集合框架分为两大类:Collection和Map.Collection以一组Object的形式保存元素,Map以Key-Value对的形式保存元素. 上图列出的类并不完整,只列举了平时比较常 ...

  2. 集合框架-ArrayList,Vector,Linkedlist

    // ClassCastException 报错,注意,千万要搞清楚类型 * Vector的特有功能: * 1:添加功能 * public void addElement(Object obj) -- ...

  3. Java基础-集合框架-ArrayList源码分析

    一.JDK中ArrayList是如何实现的 1.先看下ArrayList从上而下的层次图: 说明: 从图中可以看出,ArrayList只是最下层的实现类,集合的规则和扩展都是AbstractList. ...

  4. 大数据学习笔记——Java篇之集合框架(ArrayList)

    Java集合框架学习笔记 1. Java集合框架中各接口或子类的继承以及实现关系图: 2. 数组和集合类的区别整理: 数组: 1. 长度是固定的 2. 既可以存放基本数据类型又可以存放引用数据类型 3 ...

  5. JDK集合框架源码分析 - 简单概要

    1.类继承体系 在集合框架的类继承体系中,最顶层有两个接口Collection.Map: Collection 表示一组纯数据 Map 表示一组key-value对 Collection的类继承体系: ...

  6. JAVA基础--JAVA API集合框架(ArrayList、HashSet、HashMap使用)14

    一.集合Collection 1. 集合介绍 变量:表示的内存中的一个空间,只能保存确定类型的单个数据 数组:表示的是内存中的多个连续的空间,这些空间中可以存储多个同类型的数据. 后期继续学习面向对象 ...

  7. JDK集合框架--综述

       接下来的几篇博客总结一下对jdk中常用集合类知识,本篇博客先整体性地介绍一下集合及其主要的api: 从整体上来说,集合分两大类collection和map: 首先来看看Collection: c ...

  8. 集合框架,ArrayList和Vector的区别,让arrayList线程安全的几种方案

    boolean add(E e) 将指定的元素添加到此列表的尾部. void add(int index, E element) 将指定的元素插入此列表中的指定位置. boolean addAll(C ...

  9. 集合框架 ArrayList LinkedList(待续)

    ArrayList中存储的元素的内存空间是连续的, LinkedList内存空间不是连续的 集合对象不能被序列化到硬盘中 http://blog.csdn.net/eson_15/article/de ...

随机推荐

  1. map集合排序

    默认情况下,HashMap.HashTable.TreeMap.LinkedHashMap的排列顺序比较: package com.per.sdg.demo; import java.util.Has ...

  2. 怎样免费设置QQ空间背景音乐

    怎样免费设置QQ空间背景音乐 1.打开QQ空间,点击 2. 3. 4.这里它要求我们输入歌曲的在线路径,并且必须是MP3格式的,这就简单了,我们仅仅要去网上找在线的MP3音乐就能够了.可是如今非常多提 ...

  3. HDU2444 The Accomodation of Students —— 二分图最大匹配

    题目链接:https://vjudge.net/problem/HDU-2444 The Accomodation of Students Time Limit: 5000/1000 MS (Java ...

  4. YTU 2441: C++习题 复数类--重载运算符2+

    2441: C++习题 复数类--重载运算符2+ 时间限制: 1 Sec  内存限制: 128 MB 提交: 847  解决: 618 题目描述 定义一个复数类Complex,重载运算符"+ ...

  5. YTU 2432: C++习题 对象数组输入与输出

    2432: C++习题 对象数组输入与输出 时间限制: 1 Sec  内存限制: 128 MB 提交: 1603  解决: 1152 题目描述 建立一个对象数组,内放n(n<10)个学生的数据( ...

  6. YTU 2553: 谁是赢家

    2553: 谁是赢家 时间限制: 1 Sec  内存限制: 128 MB 提交: 94  解决: 25 题目描述 某一天,hcbbt等一群弱菜去tamara巨巨家里一起玩了一个卡牌游戏.巨 巨家里有2 ...

  7. POJ - 2516 Minimum Cost(最小费用最大流)

    1.K种物品,M个供应商,N个收购商.每种物品从一个供应商运送到一个收购商有一个单位运费.每个收购商都需要K种物品中的若干.求满足所有收购商需求的前提下的最小运费. 2.K种物品拆开来,分别对每种物品 ...

  8. 牛客练习赛13D:幸运数字Ⅳ(康托展开) F:关键字排序

    链接:https://www.nowcoder.com/acm/contest/70/D 题目: 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7. 比如说,47.744.4都是幸运数字而5.1 ...

  9. js中的call和apply方法

    call方法: 语法:call(thisObj,[arg1,arg2,arg3,...]); 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call 方法可以用来代替另一个对象调用 ...

  10. ubuntu下为thunderbird添加邮件提醒功能(转载)

    转自:http://blog.csdn.net/zhangt85/article/details/9154525 1.“工具”-->“附件组件” 2.搜索“new_mail_attention” ...