public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
(1)无参构造
public ArrayList() {
// 赋值,把一个默认长度为0的空容量的数组赋值给集合真正存储数据的容器
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
(2)有参构造
// 创建指定大小的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);
}
}
(3)指定集合的元素的列表
public ArrayList(Collection<? extends E> c) {
// 将构造方法的参数转化为数组
elementData = c.toArray();//1--2--3
// 将数组的长度赋值给size,判断是否不等于0
if ((size = elementData.length) != 0) {
// 再次进行判断
if (elementData.getClass() != Object[].class)
// 数组的创建与拷贝
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 就把空数组的地址赋值给集合存元素的数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
// 1
// 将集合转化为数组的方法
public Object[] toArray() {
// 调用数组工具类的方法,将集合存元素的数组作为第一个参数,集合的长度作为第二个参数
return Arrays.copyOf(elementData, size);
}
//2
class Arrays{
public static <T> T[] copyOf(T[] original, int newLength) {
// 再次调用方法得到数组
return (T[]) copyOf(original, newLength, original.getClass());
}
// 3
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
// 通过三目运算判断两个数组,不管结果如何,都会创建一个新的数组
// 新数组的长度一定和集合的size一样
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
// 数组的拷贝
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
// 返回新数组
return copy;
}
}
(1)add(E e)及其扩容
public boolean add(E e) {
// 进行扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// 扩容时进行调用
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 当用无参构造器实例化且第一次调用时,elementData总是会被初始化为10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 底层用到了三目运算
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 判断需要的最小容量是否超过当前elementData的容量
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩容的核心算法
// >> :表示右移,右移几就是除以2的几次幂
// << :表示左移,左移几就是乘以2的几次幂
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 扩容1.5倍后仍无法满足最小容量
if (newCapacity - minCapacity < 0)
// 那么就用该minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 数组的扩容和拷贝
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
(2)add( int index, E element )
// 在指定索引处插入元素
public void add(int index, E element) {
// 检查索引是否合法
rangeCheckForAdd(index);
// 进行扩容
ensureCapacityInternal(size + 1);
// 将目前index处和它后面的元素整体后移一个位置
System.arraycopy(elementData, index, elementData, index + 1,size - index);
// 更新该索引处的值
elementData[index] = element;
size++;
}
// 检查索引是否合法的方法
private void rangeCheckForAdd(int index) {
// 判断索引是否大于容量或小于0
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
(3) addAll(Collection extends E> c)
public boolean addAll(Collection<? extends E> c) {
// 将有数据的集合转化为数组
Object[] a = c.toArray();
// 有数据集合长度赋值给numNew
int numNew = a.length;
// 校验以及扩容
ensureCapacityInternal(size + numNew);
//进行拷贝
System.arraycopy(a, 0, elementData, size, numNew);
//集合长度进行更改
size += numNew;
//根据numNew返回是否添加成功
return numNew != 0;
}
结论:底层使用了System.arraycopy方法进行了拷贝
(4)addAll(int index, Collection extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {
// 检查索引是否合法
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
// 进行扩容
ensureCapacityInternal(size + numNew);
// numMoved :代表要移动元素的个数
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
public E set(int index, E element) {
// 检查索引是否合法
rangeCheck(index);
// 取出旧值
E oldValue = elementData(index);
// 替换旧值
elementData[index] = element;
// 返回旧值
return oldValue;
}
public E get(int index) {
// 检查索引是否合法
rangeCheck(index);
// 返回要获取的值
return elementData(index);
}
// 获取指定的元素
E elementData(int index) {
return (E) elementData[index];
}
toString是属于AbstractCollection抽象类里面的方法
public String toString() {
//获取迭代器
Iterator<E> it = iterator();
// 判断迭代器是否有元素
if (! it.hasNext())
return "[]"; //没有则返回空字符串
// 创建一个StringBuilder
StringBuilder sb = new StringBuilder();
// 先追加了'['
sb.append('[');
// 无限循环
for (;;) {
// 调用迭代器的next方法取出元素,且将光标向下移动
E e = it.next();
// 三元判断
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
//没有元素,在缓冲区的最后追加‘]’,且吧整个缓冲区的数据转化为字符串,然后再结束该方法
return sb.append(']').toString();
// 有元素就直接进行追加
sb.append(',').append(' ');
}
}
(1)删除单个元素1
// 删除指定索引处的元素
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);
// 将最后一个元素置为null
elementData[--size] = null;
// 返回被删除元素的值
return oldValue;
}
(2)删除单个元素2
// 删除指定元素
public boolean remove(Object o) {
// ArrayList中允许添加为null的元素
if (o == null) {
// 遍历并删除第一个为null的元素
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
// 该方法与remove(int index)类似,仅仅少了边界检查且没有返回值
fastRemove(index);
return true;
}
} else {
// 遍历并删除第一个相等的元素
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
// 未找到与o匹配的元素,返回false
return false;
}
(3)clear 清空元素
public void clear() {
// 实际修改次数自增
modCount++;
// 遍历集合
for (int i = 0; i < size; i++)
// 把数组中的每一个位置为null,让垃圾回收期尽早回收
elementData[i] = null;
// 把集合长度设为0
size = 0;
}
说说1.7和1.8版本初始化的时候的区别么?
1.7以前会调用this(10)才是真正的容量为10
1.8是默认走了空数组,只有第一次add的时候容量会变成10。
ArrayList是线程安全的么?
不是,Vector是线程安全版本的数组容器。
Vector的实现很简单,就是把所有的方法统统加上synchronized就
ArrayList的遍历和LinkedList遍历性能比较如何?
ArrayList比LinkedList快,ArrayList遍历最大的优势在于内存的连续性,CPU的内部缓存结构会缓存连续的内存片段,可以大幅降低读取内存的性能开销。