《arraylist源码解读》由会员分享,可在线阅读,更多相关《arraylist源码解读(7页珍藏版)》请在金锄头文库上搜索。
1、public class ArrayList extends AbstractListimplements List, RandomAccess, Cloneable, java.io.Serializable支持泛型,父类父类AbstractList:抽象类,List 接口, RandomAccess: Marker interface used by List implementations to indicate that they support fast (generally constant time) random access.标志快速随机存取 Cloneable:cloneS
2、erializable:序列化成员变量成员变量private static final long serialVersionUID = 8683452581122892189L; 序列化的版本号,需要 序列化的都要有。 private static final int DEFAULT_CAPACITY = 10; 默认的容量大小是 10private static final Object EMPTY_ELEMENTDATA = ; 空实例private static final Object DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ; EMPTY_ELEMEN
3、TDATA 与 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的区别在于,当添加完 第一个元素的时候,后者知道要扩充多少。 transient Object elementData; 这个是非常重要的成员变量,也就是把元素存储在这个 Object 类型的数组里,transient 表示这个变量不进行序列化。private int size; 就是 ArrayList 的元素的数量。构造函数构造函数public ArrayList(int initialCapacity) if (initialCapacity 0) this.elementData = new Objec
4、tinitialCapacity; else if (initialCapacity = 0) this.elementData = EMPTY_ELEMENTDATA; else throw new IllegalArgumentException(“Illegal Capacity: “+initialCapacity);第一个构造函数,传入了初始容量,如果大于 0,生成一个新对象,大小为初始容量 的,如果是等于 0,初始一个空的对象,否则抛异常。public ArrayList() this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
5、第二个构造一个空的 arrayList,初始容量为 10public ArrayList(Collection c) elementData = c.toArray();if (size = elementData.length) != 0) / c.toArray might (incorrectly) not return Object (see 6260652)if (elementData.getClass() != Object.class)elementData = Arrays.copyOf(elementData, size, Object.class); else / rep
6、lace with empty array.this.elementData = EMPTY_ELEMENTDATA;第三个构造函数,传入一个集合,先转换为一个数组,然后看长度是否为 0,如果为 0 的话就初始化空的一个对象,如果不为 0 并且不为 Object 类型的数组,就转换成 O bject 类型的。重要的成员函数public boolean add(E e) ensureCapacityInternal(size + 1); / Increments modCount!elementDatasize+ = e;return true;这个函数是添加一个元素,首先判断容量是否够,如果够
7、在数组的末尾添加新的元素, 返回成功,接下来看最重要的部分,是怎么扩展容量的,打开上面的 ensureCapacityInternal 函数。private void ensureCapacityInternal(int minCapacity) if (elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA) minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);ensureExplicitCapacity(minCapacity);private void ensureExplicitCapaci
8、ty(int minCapacity) modCount+;/ overflow-conscious codeif (minCapacity - elementData.length 0)grow(minCapacity);看上面的代码,可以知道,当要求的最小容量比现在数组的长度大的时候,就会调用 grow()函数来动态增加容量。其中有一个变量可能会比较疑惑,就是 modCount,这是干什么 的,它是 AbstractList 下的一个变量,用来记录 list 的大小变化的次数的,这个变量有什么 用呢,当进行数组循环遍历的时候,会在遍历前记住临时的 modeCount,遍历结束后, modC
9、ount 与之前的记录进行比较,如果不相等的话就抛 ConcurrentModificationException 这个异常。因为是线程不安全的,遍历的时候,如果数组的数据的元素的数量有变化会出 异常。private void grow(int minCapacity) / overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity 1);if (newCapacity - minCapacity 0)newCapacity = hugeCapa
10、city(minCapacity);/ minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);接下来认真的看 grow 这个函数,新扩充的容量是原来容量的 1.5 倍,如果还是不够, 那么新的容量就直接为所需要的最小容量,最后进行数组的扩充。public void add(int index, E element) rangeCheckForAdd(index);ensureCapacityInternal(size + 1); /
11、 Increments modCount!System.arraycopy(elementData, index, elementData, index + 1,size - index);elementDataindex = element;size+;这个函数是在某个位置添加一个元素,首先 index 会不会超出索引,超出抛异常,调 用前面分析过的容量保证的函数,其实数组在某个位置添加元素挺蛋疼的,需要把这个位 置及后面的元素都往后移一位,调用 System.arraycopy,把元素复制过去,然后空出来的那 个位置插入元素。public E remove(int index) range
12、Check(index);modCount+;E oldValue = elementData(index);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 workreturn oldValue;上面是删除的函数,先判断是否超出索引位置,然后 int numMoved = size-index-1;是什 么意思呢,
13、就是删除了某个位置的元素,对于数组来说,得把之后的元素都给往前移一个 位置的,所以得把需要移动元素的个数给算出来。所以说数组结构,增删真是蛋疼啊。public boolean remove(Object o) if (o = null) for (int index = 0; index = size)throw new NoSuchElementException();Object elementData = ArrayList.this.elementData;if (i = elementData.length)throw new ConcurrentModificationExcept
14、ion();cursor = i + 1;return (E) elementDatalastRet = i;返回下一个元素的函数,checkForComodification,它的作用上面说的 modCount 分析过了, 如果 cursor 的索引大于或者等于 size,抛 NoSuchElementException 异常,肯定没有这个元 素,如果是 cursor= elementData.length 就代表的是在这期间数组的长度变小了,有其它线 程操作的原因,抛异常 ConcurrentModificationException()。如果都没问题,cursor 加 1,然 后返回元素
15、,并且 lastRet 标记。public void remove() if (lastRet 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 !
16、= size / update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();这个函数是 java8 才有的,也就是 iterator 对 lamda 表达式的支持,就是一个遍历而已。OverrideSuppressWarnings(“unchecked“)public void sort(Comparator c) final int expectedModCount = modCount;Arrays.sort(E) elementData, 0, size, c);if (modCount != expectedModCount) throw new Concurrent