关键常量:

private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小
private static final Object[] EMPTY_ELEMENTDATA = {}; 如果elementData用这个变量初始化,则DEFAULT_CAPACITY不会参与数组大小的运算
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 如果elementData用这个变量初始化,则DEFAULT_CAPACITY会参与数组大小的运算,只有ArrayList()中有调用
transient Object[] elementData; 实际存储数据的数组
private int size; 数组大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 之所以减8是因为不同的vm有不同的保留字会占用一部分容量
 

概述:

  ArrayList是基于数组实现的一个有序的列表,允许添加null值.除了List接口中的方法外,还实现了一些操作数组元素和大小的方法,具体下面会列举。每个ArrayList实例都有一个元素数,即size属性,这个属性标注了在实例中包含了多少个元素,这些元素存储在elementData这个数组中,当实例的容量不足时,会调用grow方法进行扩容,通常情况下每次扩大一半容量,但是有两种特殊情况,一种是手动指定的容量大于当前容量的1.5倍时会按照指定容量扩容,另一种是当前容量的1.5倍大于MAX_ARRAY_SIZE这个值的时候会扩容至Integer.MAX_VALUE或MAX_ARRAY_SIZE。
 

主要方法:

1、构造方法

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) { //通过一个集合构造数组
elementData = c.toArray();
if ((size = elementData.length) != ) { //参数集合不为空,则将实例构造成Object[]
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else { //参数集合为空,则将实例构造成默认空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}

2、新增

public boolean add(E e) {
ensureCapacityInternal(size + ); //扩容操作
elementData[size++] = e;
return true;
}
public void add(int index, E element) {  //添加元素到指定位置
rangeCheckForAdd(index); //检查index是否越界 ensureCapacityInternal(size + );
System.arraycopy(elementData, index, elementData, index + ,size - index);
elementData[index] = element;
size++;
}
public boolean addAll(Collection<? extends E> c) { //将参数集合添加至实例
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew);
System.arraycopy(a, , elementData, size, numNew);
size += numNew;
return numNew != ;
}
public boolean addAll(int index, Collection<? extends E> c) { //将参数集合添加至实例指定位置
rangeCheckForAdd(index); //检查index是否越界 Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; //这里要注意,插入前会将原数组从index位置分开
if (numMoved > )
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); System.arraycopy(a, , elementData, index, numNew);
size += numNew;
return numNew != ;
}

3、覆盖

 public E set(int index, E element) {        //新增会将index位置之后的元素依次后移,而覆盖会将index位置的元素替换,对其他位置的元素没有影响
rangeCheck(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}

4、读取

 public E get(int index) {
rangeCheck(index); return elementData(index);
}

5、删除

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, //删除元素之后会将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;
}

6、清空

public void clear() {
modCount++; for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
}

7、扩容

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //当使用第一种构造方法时,第一次执行扩容方法会进入这个分支,将容量扩展为默认大小(10)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(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倍
if (newCapacity - minCapacity < 0) //特例1:参数大于数组长度的1.5倍,此时按照参数扩容
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //特例2:数组长度的1.5倍大于MAX_ARRAY_SIZE,此时将数组扩容至MAX_ARRAY_SIZE 或Integer.MAX_VALUE
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}

8、Fail-Fast机制

ArrayList的迭代器也具备快速失败机制,具体是通过checkForComodification()进行控制:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果并发线程对实例进行增删操作,则迭代器会抛出异常以防止在不确定的时间发生某种行为带来的未知风险
 

ArrayList源码阅读笔记(基于JDk1.8)的更多相关文章

  1. ArrayList源码阅读笔记(1.8)

    目录 ArrayList类的注解阅读 ArrayList类的定义 属性的定义 ArrayList构造器 核心方法 普通方法 迭代器(iterator&ListIterator)实现 最后声明 ...

  2. ArrayList源码分析笔记(jdk1.8)

    1.特点: ArrayList 是一个动态数组,它是线程不安全的,允许元素为null 可重复,插入有序 读写快,增删慢 扩容:默认容量 10,默认扩容1.5倍 建议指定容量大小,减少扩容带来的性能消耗 ...

  3. ArrayList源码分析(基于JDK1.8)

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  4. ArrayList源码阅读笔记

    ArrayList ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAcc ...

  5. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  6. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  7. CopyOnWriteArrayList源码阅读笔记

    简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...

  8. JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类

    JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类 Unsafe Java中无法直接操作一块内存区域,不能像C++中那样可以自己申请内存 ...

  9. JDK1.8源码阅读笔记(1)Object类

    JDK1.8源码阅读笔记(1)Object类 ​ Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...

随机推荐

  1. docker run mysql

    sudo docker run --name=mysqlserver -e MYSQL_ROOT_PASS=123456 -v /srv/mysql/data:/data/mysql -d -p : ...

  2. phpstorm 使用技巧

    专题1 专题2 专题3 专题4 快捷键

  3. thinkphp一句话疑难解决笔记 3

    错误调试, E($msg)? 这个是tp内置的E 方法, E 函数. 它是tp抛异常 的另外一种方式. 默认的异常处理方式是, 在 框架下的 ThinkPHP/Tpl/think_exception. ...

  4. 【bzoj1708】[USACO2007 Oct]Money奶牛的硬币

    题目描述 在创立了她们自己的政权之后,奶牛们决定推广新的货币系统.在强烈的叛逆心理的驱使下,她们准备使用奇怪的面值.在传统的货币系统中,硬币的面值通常是1,5,10,20或25,50,以及100单位的 ...

  5. 调试D2JS

    D2JS 最终加载运行于 nashorn 上,目前能调试 nashorn js 的 IDE 只有一款:NetBeans.eclipse 没有计划,神器号称支持 nashorn,对于简单类型可以观察,对 ...

  6. MarkdownPad 2 在win10下出错:HTML 渲染错误(This view has crashed) 的解决办法 + MarkdownPad2.5 注册码

    首先附上MarkdownPad2.5的注册码. 邮箱:Soar360@live.com 授权密钥: GBPduHjWfJU1mZqcPM3BikjYKF6xKhlKIys3i1MU2eJHqWGImD ...

  7. 百度地图多点路径加载以及调整页面js

    $(document).ready(function () { /*用正则表达式获取url传递的地址参数,split后获得地址数组*/ bmap = new BMap.Map('mapcontaine ...

  8. ComboBox,三级联动菜单,新入门点小白,有些代码有待优化,大神勿喷

    //当前窗体的Load事件 private void provinceANDCity_Load(object sender, EventArgs e) { //连接字符串 string strConn ...

  9. Ajax发送POST请求SpringMVC页面跳转失败

    问题描述:因为使用的是SpringMVC框架,所以想使用ModelAndView进行页面跳转.思路是发送POST请求,然后controller层中直接返回相应ModelAndView,但是这种方法不可 ...

  10. PHP基础

    $a=10; //$b="hello";//$a=(string)$a; 强制转换A的类型为字符串 //settype($a,"string");//var_d ...