ArrayList类图结构
需要查看
Iterable顶层接口,点一下Iterable顶层接口分析
Collection接口分析,点一下Collection接口分析
AbstractCollection抽象类分析,点一下:AbstractCollection抽象类分析
AbstractList抽象类分析,点一下:AbstractList抽象类分析
类的结构
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
}
继承了AbstractList接口
实现了List接口、RandomAccess接口、Cloneable克隆接口、Serializable序列化接口
类的属性
//默认初始量
private static final int DEFAULT_CAPACITY = 10;
//定义一个空的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//transient加上的意思是将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化
//集合装载数据,使用数组进行装载
transient Object[] elementData;
//集合大小
private int size;
集合初始化
//提供带初始化容量的数组初始化
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//初始化数组
this.elementData = new Object[initialCapacity];
}
//声明一个空集合
//与Vector集合的不同是,Vector初始化设置了一个为10的数组,而ArrayList直接设置为空数组
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;//详见类属性(静态且不可变的一个空数组)
}
//将一个集合提供给ArrayList进行初始化:处理方式跟Vector集合一致
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
核心方法解析(主要包含底层集合数组扩容)
//将集合压缩(将集合中没有存储元素的部分删除)这个是改变底层存储集合数组的数组大小
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
//确保数组容量够不够minCapacity最少需要的容量大小
public void ensureCapacity(int minCapacity) {
//如果数组为空,最小最快默认为0,是否就使用默认增长量10
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
//
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
//确保容量,
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
//判断要不要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//数组扩容minCapacity最小容量
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//数组长度
//新的容量=原数组长度+原数组长度/2
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量大于最小容量时,取最小容量;否则取新容量,然后还要根据
//新容量是否超过Int最大值以及Int-8(int-8再说一次防止内存溢出,因为JVM底层在数组头部加了一些默认的数据
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);
}
//超大容量--获取集合最大容量
//正常为Int-8,如果超过这个值时直接返回Int的最大值
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
核心方法解析
//给定元素在素组的位置(从0开始)
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;
}
//给定元素在数组的位置(从后往前找size开始找)
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;
}
//转数据,思路就是使用底层native进行数组拷贝
public Object[] toArray() {
//拷贝数组elementData,拷贝长度为当前数组的元素个数
return Arrays.copyOf(elementData, size);
}
//转数据,思路就是使用底层native进行数组拷贝
public Object[] toArray() {
//拷贝数组elementData,拷贝长度为当前数组的元素个数
return Arrays.copyOf(elementData, size);//这个拷贝是基于JVM的,速度相当快,Duang的一下就过去了
}
//告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
@SuppressWarnings("unchecked")
//默认default只能在 同一包内可见,所以外面访问不到也无法访问
default E elementData(int index) {
//通过索引获取数组中元素
return (E) elementData[index];
}
//根据给定索引,获取数组中元素
public E get(int index) {
//rangeCheck:注释部分为rangeCheck内部实现,判断是否是否越界
// if (index >= size)
// //outOfBoundsMsg:return "Index: "+index+", Size: "+size;
// throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
rangeCheck(index);
//获取元素
return elementData(index);
}
//设置某个元素在给定索引位置
public E set(int index, E element) {
rangeCheck(index);//判断给定索引是否超过元素个数
//获取旧元素
E oldValue = elementData(index);
//给旧元素位置设置新元素
elementData[index] = element;
return oldValue;//返回旧元素
}
//添加某个元素到数组
public boolean add(E e) {
//这里面已经完成了modCount++;
ensureCapacityInternal(size + 1); // Increments modCount!!
/**
* --size++
* 先执行+1后使用
* 2个步骤
* 1、将数组的元素个数+1;
* 2、给size+1的位置设置新元素
*/
elementData[size++] = e;
return true;
}
//在数组某个位置添加元素
//1、首先要判断当前添加的位置是否超过数组大小(越界问题)以及添加的index必须的大于0吧
//2、数据要不要扩容
//3、数据拷贝【将加入的元素放到数组中】
//--先把要加入数组的元素位置空出来,通过拷贝移动的方式
//--System.arraycopy(数组,开始拷贝的位置,要拷贝的数据到,拷贝到哪里(开始拷贝的位置 + 1),拷贝长度(size - index));
//--这个意思就是把数组往后面移一个位置
//4、然后将空出来的位置把要加入的元素给填进去elementData[index] = element;
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;//最后将数组大小+1
}
//给定索引的位置的数组元素要移除
//如果我自己做思路怎么搞?
//1、首先的判断移除的原生位置,是不是索引越界(大于0小于size)
//2、modCount要加1
//3、把要移除的位置元素取出来放起,用于返回用
//4、把数据要删除的位置给通过数组拷贝的方式释放出来;数组要减容
//5、System.arraycopy(数组,开始拷贝的位置(index+1),要拷贝的数据到,拷贝到哪里(index),拷贝长度(size - index - 1));
//6、然后将数组最后一个位置设置为null(主要是让GC回收)
//7、size--
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//这里这样做的目的就是为了防止:要移除的位置就是在size位置
int numMoved = size - index - 1;//-1的目的就是数组索引为0开始算;size为个数1开始算;
//如果移除的元素不在数组末尾时,需要将数组往前移
if (numMoved > 0)
//要拷贝的数组、源数组要复制的起始位置(因为要删除,所以从Index+1开始拷贝)、拷贝到的数组、目的数组放置的起始位置、复制的长度
System.arraycopy(elementData,index+1,elementData,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;
}
//fastRemove跟remove(int index)功能一样,只是少了越界判断
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
//将数组元素设置为null,GC回收
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//判断扩容及modCount++
ensureCapacityInternal(size + numNew); // Increments modCount
//将新数组拷贝数组中
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;//将size设置为size+numNew
return numNew != 0;
}
ArrayList迭代器
//
public Iterator<E> iterator() {
return new Itr();
}
//这个跟Vector集合功能一致
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//这句话没有是吗用;Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
//elementData和这个ArrayList内提供了此方法
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
总观:
Vector和ArrayList其实底层实现都是一样的,只是Vector集合在动集合数组的时候方法上面加了synchronized已保证接口安全;而ArrayList为线程不安全的集合,但是效率上ArrayList》Vector接口的;
List总结:
可以重复,通过索引取出加入数据,顺序与插入顺序一致,可以含有null元素
ArrayList:底层数据结构使数组结构array,查询速度快,增删改慢,因为是一种类似数组的形式进行存储,因此它的随机访问速度极快;
Vector:底层是数组结构array,与ArrayList相同,查询速度快,增删改慢;
LinkedList:底层使用链表结构,增删速度快,查询稍慢;
ArrayList与Vector的区别:
1.如果集合中的元素数量大于当前集合数组的长度时,Vector的增长率是目前数组长度的100%,而ArryaList增长率为目前数组长度的50%。所以,如果集合中使用数据量比较大的数据,用Vector有一定优势
2.线程同步ArrayList是线程不同步,所以Vector线程安全,但是因为每个方法都加上了synchronized,所以在效率上小于ArrayList