1,概念
ArrayList是一个其容量能够动态增长的动态数组,但和数组会有点不一样。下面细说
特性:将会在下面的源码片段中发现,没有一个代码片段使用synchronized关键字
因此,ArrayList是线程不安全的,建议在单线程中使用
2,类关系图
3,走进源码
数据结构
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//默认存储区
transient Object[] elementData
//数组长度
private int size;
还有两个字段
官方解释:用于空实例的共享空数组实例
这个用于在new对象指定大小为0的时候,初始化ArrayList,下面的构造函数可以看到
private static final Object[] EMPTY_ELEMENTDATA = {};
官方解释:共享的空数组实例用于默认大小的空实例。我们将其与EMPTY_ELEMENTDATA区别开来,以了解添加第一个元素时需要充气多少
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
3.1 构造函数
构造一个指定大小的ArrayList
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果指定大小为0的时候,
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
空构造函数,构造一个默认大小的实例
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
根据一个集合,来构造一个新的ArrayList,并带有集合元素数据
public ArrayList(Collection<? extends E> c) {
//将集合转换为数组类型
elementData = c.toArray();
if ((size = elementData.length) != 0) {
//如果elementData不是Object[]类型的话,就转换一下
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//c集合的长度为0的时候
this.elementData = EMPTY_ELEMENTDATA;
}
}
3.2添加元素
public boolean add(E e) {
//size+1:预计新添元素后的数组大小
//保证有足够的容量存储数据元素
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal()方法,
private void ensureCapacityInternal(int minCapacity) {
//这个是是否需要扩容 这个是计算实际容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
ensureExplicitCapacity(int )方法,根据calculateCapacity()方法的返回值判断是否够容量,按需要会都自动扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//minCapacity是预计新添元素后的容量
//预计新添元素后大小与原始数组大小相比
if (minCapacity - elementData.length > 0)
//大于0,表示默认容量不够用了,需要扩容
grow(minCapacity);
}
grow()方法。扩容机制
当elementData.length=0的时候,直接令newCapacity = minCapacity
当elementData.length!=0,原始长度+原始长度/2 标准来扩容
(当然,不允许长度超过最大正整数)
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//原始长度+原始长度/2
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
hugeCapacity()方法。判断当前容量是否超过最大正整数
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
calculateCapacity()方法,计算容量,用于构造(扩容)一个数组存储对象
当新添元素后:
当elementData ={}时候,返回10,用于构造一个长度为10的object【】对象
当elementData !={}时候,
1,默认容量10还够用,则返回10
2,超出了默认容量10 ,则返回size+1(10+1),也就是动态扩容
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果elementData={},那么返回一个最大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//用(size+1)与默认大小相比,谁大返回谁,
//该返回值用于判断将要新添的元素是否还有容量
//minCapacity等同于size+1
return Math.max(DEFAULT_CAPACITY(值为10), minCapacity);
}
return minCapacity;
}
3.3删除元素
方法1,根据指定下标删除元素
public E remove(int index) {
//判断下标是否超出长度
rangeCheck(index);
modCount++;
//返回指定下标的值
E oldValue = elementData(index);
//将要移动元素的个数
int numMoved = size - index - 1;
if (numMoved > 0)
//将index后面的元素整体向前移动一步
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将末端的元素置空
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
elementData()方法,返回指定下标的元素
E elementData(int index) {
return (E) elementData[index];
}
方法2,根据指定元素的值删除
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;
}
fastRemove()方法
官方解释:专用的remove方法,跳过边界检查,并且不返回删除的值
private void fastRemove(int index) {
modCount++;
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
}
方法三,删除所有元素
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
方法四,删除从fromIndex 到toIndex 区域的元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
3.4 更改元素
- set(int index, E element):将指定下标的元素设为element
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
- sort(Comparator<? super E> c):按照指定的排序规则排序
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
- subList( int from , int to ):返回从from到to之间的列表
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
- toArray():将列表转化为数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
- trimToSize( ):修改当前实例的容量是列表的当前大小
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
3.5 查找
- contains(Object o):如果包含元素o,则返回为true
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
- indexOf( Object o ):返回此列表中指定元素的第一次出现的索引,如果列表不包含,返回-1
indexof()
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;
}
- get(int index):返回指定索引的元素
public E get(int index) {
rangeCheck(index);
return elementData(index);
}