Arraylist终结版
通过源码的分析掌握arraylist的特性和功能,使得我们在使用arraylist的时候能知道使用他会给我们的程序产生什么影响
Arraylist的源码中的继承的类和接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
AbstractList抽象类,在其中定义了Arraylist需要继承或者重写的一些add, get ,set, remove的方法。
List 接口是为了让变量引用时可以用List 作为引用变量类型
RandomAccess:随机地址访问,RandomAccess接口这个空架子的存在,是为了能够更好地判断集合是否ArrayList或者LinkedList,从而能够更好选择更优的遍历方式,提高性能!
Cloneable:可以使用对象clone
Serializable:可以序列化
Arraylist的源码中的成员
//初始容量大小
private static final int DEFAULT_CAPACITY = 10;
//空的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认存放元素空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//transient :表示该变量不会被序列化,存放元素的数组引用变量
transient Object[] elementData; // non-private to simplify nested class access
//elementData中存放元素的个数
private int size;
//
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//对list操作的次数
protected transient int modCount = 0;
Arraylist的源码中的方法
构造方法
- 有参构造方法:int initialCapacity 表示给定一个int类型,作为初始容量
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//初始容量为 initialCapacity
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//给一个length大小为0的空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
- 无参构造方法
public ArrayList() {
//给一个默认的数组,该数组length 为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 有参构造方法:传入一个集合(实现Collection接口)
public ArrayList(Collection<? extends E> c) {
//c对象调用toArray的方法返回一个数组
elementData = c.toArray();
//判断数组大小并赋值给成员变量size
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
//通过Arrays的静态方法返回一个数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.将一个空的数组赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
}
}
trimToSize()
这方法用的比较少。修剪多出的空间,将elementData的length修剪到变量size的大小,比较简单就描述
public void trimToSize() {
//modCount 一种快速失败机制,记录对list的修改次数:用于在list遍历的时候,防止修改对list的修改。
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
add()
add方法添加一个变量 e
public boolean add(E e) {
//对当前数组的容量进行一个判断是否需要扩容或者实现扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;//末尾赋值
return true;
}
//返回一个扩容的值
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断elementData是否为一个默认空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//判断是否扩容
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//执行扩容
private void ensureExplicitCapacity(int minCapacity) {
//修改次数加一
modCount++;
// overflow-conscious code
//判断是否需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//开始扩容
private void grow(int minCapacity) {
// overflow-conscious code
//原有的容量大小
int oldCapacity = elementData.length;
//扩容的大小 >> 是位运算 (二进制向右移一位)>>1 相当与除以2
int newCapacity = oldCapacity + (oldCapacity >> 1);
//当前这个时候的minCapacity = size +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:
//通过调用Arrays的静态方法,扩容过后的数组赋值给elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
//控制扩容大小的范围,最大为 Integer.MAX_VALUE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
add方法指定一个位置添加一个变量 e
public void add(int index, E element) {
//判断index 是否越界,比较简单,与成员变量size 比较
rangeCheckForAdd(index);
//前面描述过,扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// index 后面的元素向后移动一个位置
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 修改数组index 的值
elementData[index] = element;
//list的数组元素大小加一
size++;
}
其他addall()也比较简单,与add 基本上类似
ensureCapacity
对Arraylist底部的数组elementData进行扩容
public void ensureCapacity(int minCapacity) {
//获得arraylist的默认数组大小
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
//大于默认的数组大小进行扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
后面的都比较简单就描述下
contains ,indefxOf,lastIndexOf
public boolean contains(Object o) {
return indexOf(o) >= 0;//返回元素在list的位置是否大于等于0
}
public int indefxOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)//循环找到是否有为null的index
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)//循环比较是否有值相同对象.
if (o.equals(elementData[i])) // 这是一种健壮性的代码写法,不会造成 (null).equals()发生
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;
}
clone,toArray,get,set,elementData,clear
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
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);
}
}
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public E get(int index) {
rangeCheck(index);//判断index是否越界
return elementData(index);
}
public E set(int index, E element) {
rangeCheck(index);//判断index是否越界
E oldValue = elementData(index);//获取index的value
elementData[index] = element;
return oldValue;
}
//获取index的value
E elementData(int index) {
return (E) elementData[index];
}
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
remove
remove和add 类似比较简单
public E remove(int index) {
rangeCheck(index);//判断index是否越界
modCount++;//修改次数加一
E oldValue = elementData(index);
int numMoved = size - index - 1;//需要移动元素的个数
if (numMoved > 0)
//index 后面的元素向前移动一位覆盖index的值
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work 将最后一个元素赋值null
return oldValue;
}
Arralist 的遍历 (2种不常见的)
Iterator的遍历方式
值得注意的地方在 list.iterator()(或者list.listIterator()); 会new itr对象,在初始化的时候会将 int expectedModCount = modCount; 因此如果我们在遍历的过程种修改 list 会报错,这个时候就需要通过调用itr对象中的方法对list修改。
static ArrayList<String> list = new ArrayList();
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++){
list.add(String.valueOf(i));
}
System.out.println("Iterator的遍历方式:");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
// list.add("sss"); 会报错
// iterator.remove(); 才能删除
System.out.println(iterator.next());
}
}
public Iterator<E> iterator() {
return new Itr();
}
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();
}
}
forEach
这个我也不太熟悉通过调用forEach方法,这个2种方式,可以通过lambda 方式,函数编程
list.stream().forEach(item -> System.out.println(item));
list.forEach(item -> System.out.println(item));
=================================================
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);调用函数中的行为
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
===================================================
//函数接口
public interface Consumer<T> {
void accept(T t); //表示行为
//如果要在接口中写实现方法需要default有点类似抽象类
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
因为我也不是太熟悉,为了防止误导,暂时不解析
subList
和Iterator类似,也比较简单就就简单总结下
private class SubList extends AbstractList implements RandomAccess 是Arraylist的一个内部类
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
可以看到,SubList中并没有数组、列表之类的属性来存储数据,这进一步说明了,subList方法返回的只是一个视图。 之前说过,对subList方法返回的列表进行修改,源列表也会跟着发生变化,下面是SubList的set方法
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e); //parent.modCount 加一
this.modCount = parent.modCount; //重新赋值
this.size++;
}
接着,看一下ArrayList中的add方法,注意:代码中调用的是list.add而不是subList.add,所以需要看ArrayList的add源码:
this.modCount = parent.modCount; 重新赋值.
subList方法传入的参数是左闭右开的
ArrayList.subList方法返回的只是视图
subList的所有操作都是在操作源列表ArrayList,所以增删改都会以影响源列表。
对ArrayList进行添加、删除的操作之后,再操作subList会抛出异常
仅仅subList操作并不会抛出异常