目录
一、ArrayList 类
二、ArrayList属性
三、ArrayList构造方法
四、ArrayList常用方法
这里分析jdk 1.8,包含一些1.8新特性的源码
继承树如下:
宏观上说,ArrayList是基于动态数组 实现的,数组具有按索引查找的特性,所以访问很快,适合经常查询的数据。
public class ArrayList
extends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializable
//序列号
private static final long serialVersionUID = 8683452581122892189L;
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//一个空数组,当用户指定该 ArrayList 容量为 0 时,返回该空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
/*一个空数组实例
* - 当用户没有指定 ArrayList 的容量时(即调用无参构造函数),返回的是该数组==>刚创建一个 ArrayList 时,其内数据量为 0。
* - 当用户第一次添加元素时,该数组将会扩容,变成默认容量为 10(DEFAULT_CAPACITY) 的一个数组===>通过 ensureCapacityInternal() 实现
* 它与 EMPTY_ELEMENTDATA 的区别就是:该数组是默认返回的,而后者是在用户指定容量为 0 时返回*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList基于数组实现,用该数组保存数据, ArrayList 的容量就是该数组的长度
//该值为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入 ArrayList 中时,数组将扩容值
private transient Object[] elementData; //transient:在采用Java默认的序列化机制的时候,被该关键字修饰的属性不会被序列化。
//ArrayList实际存储的数据数量
private int size;
//创建一个初试容量的、空的ArrayList,当初试容量值非法(小于0)时抛出异常
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
//无参构造函数:创建一个 空的 ArrayList,此时其内数组缓冲区 elementData = {}, 长度为 0,当元素第一次被加入时,扩容至默认容量 10
public ArrayList() {
super();
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//创建一个包含collection的ArrayList,要放入 ArrayList 中的集合其内元素将会全部添加到新建的 ArrayList 实例中
public ArrayList(Collection extends E> c) {
elementData = c.toArray(); //将集合转化成Object[]数组
size = elementData.length; //把转化后的Object[]数组长度赋值给当前ArrayList的size,并判断是否为0
// c.toArray might (incorrectly) not return Object[] (see 6260652)
// 这句话意思是:c.toArray 可能不会返回 Object[],可以查看 java 官方编号为 6260652 的 bug
if (elementData.getClass() != Object[].class) { // 若 c.toArray() 返回的数组类型不是 Object[],则利用 Arrays.copyOf(); 来构造一个大小为 size 的 Object[] 数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 替换空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
public void trimToSize()
将数组缓冲区大小调整到实际 ArrayList 存储元素的大小
public void trimToSize() { // modCount 是 AbstractList 的属性值:protected transient int modCount = 0; // [问] modCount 有什么用? modCount++; // 当实际大小 < 数组缓冲区大小时 // 如调用默认构造函数后,刚添加一个元素,此时 elementData.length = 10,而 size = 1 // 通过这一步,可以使得空间得到有效利用,而不会出现资源浪费的情况 if (size < elementData.length) { // 注意这里:这里的执行顺序不是 (elementData = (size == 0) ) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); // 而是:elementData = ((size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size)); // 这里是运算符优先级的语法 // 调整数组缓冲区 elementData,变为实际存储大小 Arrays.copyOf(elementData, size) //先判断size是否为0,如果为0:实际存储为EMPTY_ELEMENTDATA,如果有数据就是Arrays.copyOf(elementData, size) elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
public void ensureCapacity(int minCapacity)
指定 ArrayList 的容量
public void ensureCapacity(int minCapacity) { // 最小扩充容量,默认是 10 //这句就是:判断是不是空的ArrayList,如果是的最小扩充容量10,否则最小扩充量为0 //上面无参构造函数创建后,当元素第一次被加入时,扩容至默认容量 10,就是靠这句代码 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; // 若用户指定的最小容量 > 最小扩充容量,则以用户指定的为准,否则还是 10 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
private void ensureCapacityInternal(int minCapacity):明确 ArrayList 的容量,提供给本类使用的方法
private void ensureExplicitCapacity(int minCapacity):明确 ArrayList 的容量,用于内部优化,保证空间资源不被浪费:尤其在 add() 方法添加时起效
private void grow(int minCapacity):扩容,以确保 ArrayList 至少能存储 minCapacity 个元素
private static int hugeCapacity(int minCapacity):大容量分配,最大分配 Integer.MAX_VALUE
返回ArrayList实际存储的元素数量
public int size() { return size; }
判断ArrayList是否有元素
public boolean isEmpty() { return size == 0; }
是否包含o元素
public boolean contains(Object o) { // 根据 indexOf() 的值(索引值)来判断,大于等于 0 就包含 // 注意:等于 0 的情况不能漏,因为索引号是从 0 开始计数的 return indexOf(o) >= 0; }
public int indexOf(Object o)
顺序查找,返回元素的最低索引值(最首先出现的索引位置)
public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
public int lastIndexOf(Object o)
逆序查找,返回元素的最低索引值(最首先出现的索引位置)
public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; }
public Object clone()
实现的有Cloneable接口,深度复制:对拷贝出来的 ArrayList 对象的操作,不会影响原来的 ArrayList
public Object clone() { try { // Object 的克隆方法:会复制本对象及其内所有基本类型成员和 String 类型成员,但不会复制对象成员、引用对象 ArrayList> v = (ArrayList>) super.clone(); // 对需要进行复制的引用变量,进行独立的拷贝:将存储的元素移入新的 ArrayList 中 v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } }
返回 ArrayList 的 Object 数组
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
public E get(int index)
获取指定位置上的元素,从0开始
public E get(int index) { rangeCheck(index);//检查是否越界 return elementData(index); } // 检查数组是否在界线内 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
public E set(int index, E element)
设置 index 位置元素的值
public E set(int index, E element) { rangeCheck(index);//越界检查 E oldValue = elementData(index);//获取旧数值 elementData[index] = element; return oldValue; }
public boolean add
增加指定的元素到ArrayList的指定位置,默认最后位置
public boolean add(E e) { // 确定ArrayList的容量大小---严谨 // 注意:size + 1,保证资源空间不被浪费, // ☆☆☆按当前情况,保证要存多少个元素,就只分配多少空间资源 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //在这个ArrayList中的指定位置插入指定的元素 public void add(int index, E element) { rangeCheckForAdd(index);//判断角标是否越界 //看上面的,size+1,保证资源空间不浪费,按当前情况,保证要存多少元素,就只分配多少空间资源 ensureCapacityInternal(size + 1); // Increments modCount!! //第一个是要复制的数组,第二个是从要复制的数组的第几个开始, // 第三个是复制到那,四个是复制到的数组第几个开始,最后一个是复制长度 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
public E remove
移除指定位置的元素 或者指定元素
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; return oldValue; } //移除list中指定的第一个元素(符合条件索引最低的) 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; }
更多方法请移步ArrayList源码分析