刚入java不久的程序猿,对于简单的使用已毫不满足,最终为了一探究竟,翻开了JDK的源码,以下观点为自己的理解及看了多篇博客的总结,欢迎各位大神指出不对的地方,当然也欢迎和我一样刚学的同学,一起加油努力吧~~
ArrayList是什么 |
ArrayList是一个基于数组实现的集合,它不像数组一样定长,会动态扩容,由于ArrayList是基于数组实现的,所以也决定了它的特性,查询快,增删慢,ArrayList放入值可重复,在线程安全方面,ArrayList是线程不安全的
ArrayList源码解析 |
首先一如既往的分析一下整体的体系,下面上源码
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
...
}
我们这里可以看到ArrayList继承了AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这几个接口,后几个接口使ArrayList支持序列化,克隆以及随机访问,简单的说明几个接口后,我们进入AbstractList中看一下
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
...
}
AbstractList这个抽象类,这个抽象类继承了AbstractCollection并且同样实现了List接口,稍后我们看一下List接口中的方法,接下来我们继续深入,进入AbstractCollection中看一看
public abstract class AbstractCollection<E> implements Collection<E> {
...
}
public interface Collection<E> extends Iterable<E> {
...
}
/**
* 迭代接口
*/
public interface Iterable<T> {
Iterator<T> iterator();
}
这里我们可以看到AbstractCollection实现了Collection,这里我把一层一层进入后的源码都贴出来了,最终到达一个迭代的接口,记得在上一篇博客中已经说过,所有集合最终都是通过迭代完成的,一层一层看完,我们首先看下Collection这个重要的接口
public interface Collection<E> extends Iterable<E> {
/**
* 获得list长度
*/
int size();
/**
* 判断是否为空
*/
boolean isEmpty();
/**
* 判断是否包含此元素
*/
boolean contains(Object o);
/**
* 迭代方法
*/
Iterator<E> iterator();
/**
* 转换成数组,类型为Object
*/
Object[] toArray();
/**
* 入参数组,出参数组,<T>定义的泛型为T
*/
<T> T[] toArray(T[] a);
/**
* 新增元素,返回boolean
*/
boolean add(E e);
/**
* 移除元素,返回boolean
*/
boolean remove(Object o);
/**
* 判断是否包含该集合中所有元素
*/
boolean containsAll(Collection<?> c);
/**
* 将集合中所有元素添加到list中
*/
boolean addAll(Collection<? extends E> c);
/**
* 移除该集合中所有元素
*/
boolean removeAll(Collection<?> c);
/**
* 是否包含该集合中所有元素
*/
boolean retainAll(Collection<?> c);
/**
* 清空list
*/
void clear();
/**
* 判断值是否相等
*/
boolean equals(Object o);
/**
* 计算哈希值
*/
int hashCode();
}
这里列出了Collection接口里的方法,都标了注释,大家可以了解下每个方法具体作用,接下来看下List接口里的方法,因为有很多方法和Collection里相同,所以这里只列出部分
public interface List<E> extends Collection<E> {
/**
* 根据下标index获取某个元素
*/
E get(int index);
/**
* 替换下标为index的元素
*/
E set(int index, E element);
/**
* 在下标为index处添加元素
void add(int index, E element);
/**
* 移除下标为index的元素
*/
E remove(int index);
/**
* 从前向后查找是否存在此元素,存在返回其位置,不存在返回-1
*/
int indexOf(Object o);
/**
* 从后向前查找是否存在此元素,存在返回其位置,不存在返回-1
*/
int lastIndexOf(Object o);
}
看完List接口后,我们就开始正式看ArrayList中的实现了,和之前一样,我们先来看一下定义的变量
/**
* 版本号
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认容量10(也就是数组的长度),当无参数时会用到默认的
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用来清空的空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 元素添加后的数组
*/
private transient Object[] elementData;
/**
* 数组的长度(集合中元素的个数)
*/
private int size;
下面是ArrayList的几个构造方法
/**
* 传入参数初始化容量,当初始化容量小于0时,抛出异常,否则创建数组并赋值
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* 无参构造,将空数组赋值给elementData
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
/**
* 参数为集合的构造方法
*/
public ArrayList(Collection<? extends E> c) {
//将集合转换为数组
elementData = c.toArray();
//获得当前数组长度
size = elementData.length;
//如果所获取的类的类型不一样则调用Arrays的copyOf方法,将数组复制到elementData中
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
看完ArrayList的构造方法,接下来看一下其中的方法
/**
* 将数组缓冲区大小调整到实际大小
* 举个例子说明下:比如你创建了一个集合,第一次增加元素时,数组会进行默认长度的扩容
* 默认长度为10,而你的集合中只有一个元素,这个方法就是将多余的空间释放,减少空间浪费
*/
public void trimToSize() {
//修改次数增加
modCount++;
if (size < elementData.length) {
//这里的赋值就是用来释放空间的
elementData = Arrays.copyOf(elementData, size);
}
}
/**
* 确认容量大小,当容量不足时进行扩容
*/
public void ensureCapacity(int minCapacity) {
//最小扩容容量(如果不为空集合,则为任意大小,否则为默认大小)
int minExpand = (elementData != EMPTY_ELEMENTDATA)
? 0
: DEFAULT_CAPACITY;
//当传入的扩容容量大于最小扩容容量时,用传入容量进行扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
/**
* 返回元素的个数
*/
public int size() {
return size;
}
/**
* 判断是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 判断集合中是否包含该元素
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* 从前往后查询有没有这个元素,返回下标,没有返回-1
*/
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;
}
/**
* 从后往前查询有没有这个元素,返回下标,没有返回-1
*/
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;
}
/**
* 利用Arrays的copyOf方法将集合转换为数组
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/**
* 将参数数组转换为包含当前List的数组
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
/**
* 获得当前下标的元素
*/
public E get(int index) {
//判断区间是否符合要求
rangeCheck(index);
//返回该元素
return elementData(index);
}
/**
* 判断获取值是否大于或等于当前元素数量
* 如大于或等于,则抛出异常
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 当下标index处有值时,向下标为index处赋值并返回旧值
*/
public E set(int index, E element) {
//判断区间是否符合要求
rangeCheck(index);
//获得原先index处的值
E oldValue = elementData(index);
//更换index处元素
elementData[index] = element;
return oldValue;
}
/**
* 新增元素
*/
public boolean add(E e) {
//确定容量大小,若小了,则扩容
ensureCapacityInternal(size + 1);
//添加元素
elementData[size++] = e;
return true;
}
/**
* 确定ArrayList容量,不够则扩容
*/
private void ensureCapacityInternal(int minCapacity) {
//如果elementData为空数组,则最小容量为默认容量和最小容量间的最大值
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
/**
* 明确ArrayList容量,不够则扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
//修改次数增加
modCount++;
//如果最小容量大于数组的大小,则调用grow方法
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 数组缓冲区最大存储容量
* Integer最大值减去8
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 真正的扩容方法
*/
private void grow(int minCapacity) {
//数组当前大小
int oldCapacity = elementData.length;
//新的容量为旧容量*150%,oldCapacity右移一位相当于除以2
int newCapacity = oldCapacity + (oldCapacity >> 1);
//新的容量如小于最小容量,则使用最小容量进行扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//新的容量如大于数组的最大容量,则使用最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//调用Arrays的copyOf进行扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
* 最大容量
* 当传入最小容量小于0,抛出异常
* 传入最小容量大于数组最大容量时,返回Integer最大值,否则返回数组最大容量
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
/**
* 根据下标移除元素
*/
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);
//将最后一位赋空值,等待GC回收
elementData[--size] = null; // clear to let GC do its work
//返回原先的值
return oldValue;
}
/**
* 移除传入的某个元素
*/
public boolean remove(Object o) {
if (o == null) {
//为空时进入,找到空元素,调用fastRemove方法
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//不为空时进入,找到元素,调用fastRemove方法
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* 快速删除下标为index的元素
*/
private void fastRemove(int index) {
//修改次数增加
modCount++;
//计算开始移动的下标
int numMoved = size - index - 1;
if (numMoved > 0)
//复制元素
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将最后一位赋空值,等待GC回收
elementData[--size] = null; // clear to let GC do its work
}
/**
* 清空ArrayList
*/
public void clear() {
//修改次数增加
modCount++;
//循环,将每个元素都置空,长度置为0
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
/**
* 将集合中所有值全部加入arraylist中
*/
public boolean addAll(Collection<? extends E> c) {
//将传入集合转换为数组
Object[] a = c.toArray();
//转换后数组长度
int numNew = a.length;
//进行扩容操作
ensureCapacityInternal(size + numNew);
//从末尾开始添加该数组
System.arraycopy(a, 0, elementData, size, numNew);
//改变元素个数
size += numNew;
return numNew != 0;
}
/**
* 在下标为index处将集合中所有元素添加到arraylist中
*/
public boolean addAll(int index, Collection<? extends E> c) {
//判断区间是否正确
rangeCheckForAdd(index);
//将传入集合转为数组
Object[] a = c.toArray();
//获得转换后数组长度
int numNew = a.length;
//进行扩容操作
ensureCapacityInternal(size + numNew); // Increments modCount
//获取移动时下标位置
int numMoved = size - index;
//进行2次数组复制,一次为传入集合转的数组,一次为index下标后的数组
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
//更新元素个数
size += numNew;
return numNew != 0;
}
/**
* 新增时判断区间,当index大于当前元素数量或小于0,抛出异常
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
这里基本列出了ArrayList的大部分方法,还有部分就不做解释了,基本很少用到,感兴趣的同学可以自己打开源码研究一下