关键常量:

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. 使用Gitblit 在windows 上部署你的Git Server

    Gitblit: 在windows 上部署你的Git Server 前言 之前在dudu的文章里看到过用bonobogit 部署在 IIS 7.5 上的Window 平台的git 服务器.学着部署使用 ...

  2. codevs3304 水果姐逛水果街

    题目描述 Description 水果姐今天心情不错,来到了水果街. 水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. 学过oi的水果姐迅速发现了 ...

  3. frame和bounds

    - frame 是一个以**父视图**为坐标系的位置- bounds 是一个以**自身**为坐标系的位置- 如果改变了bounds 那么会影响子控件的显示位置

  4. 关于形变属CGAffineTransform性介绍

    CGAffineTransformMakeTranslation每次都是以最初位置的中心点为起始参照 CGAffineTransformTranslate每次都是以传入的transform为起始参照, ...

  5. Codility NumberSolitaire Solution

    1.题目: A game for one player is played on a board consisting of N consecutive squares, numbered from ...

  6. discuz首页设置默认地址不带forum.php后缀的方法

    最近在研究discuz,上传安装几部搞定,打开首页跳到含有"/forum.php"的网址,到管理中心改了好一会儿也没好.那么如何实现discuz首页设置不带forum.php后缀呢 ...

  7. Linux SVN 命令详解

    1.将文件checkout到本地目录 svn checkout path(path是服务器上的目录)   例如:svn checkout svn://192.168.1.1/pro/domain    ...

  8. Sql Server函数全解<三>数据类型转换函数和文本图像函数

    阅读目录 一:数据类型转换函数 二:文本和图像函数 一:数据类型转换函数 在同时处理不同数据类型的值时,SQL Server一般会自动进行隐士类型转换.对于数据类型相近的值是有效的,比如int和flo ...

  9. ubuntu 搞坏了sudoers文件之修复方案

    pkexec visudo askubuntu原回答摘抄如下 On a modern Ubuntu system (and many other GNU/Linux distributions), f ...

  10. 保存emoji到数据库

    /// <summary> /// <summary> /// 字符串转Unicode /// </summary> /// <param name=&quo ...