【小笨鸟看JDK1.7集合源码之二】ArrayList源码剖析
2016-04-18 20:10
477 查看
主要是参考大神兰亭风雨的博客;
ArrayList简介
(1) ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
(2) ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
(3) ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
ArrayList(JDK1.7)源码详细剖析注释
还是总结一下
(1)其实源码里面还是有一些代码不太懂,例如modCount变量,只知道是与线程安全相关,ArrayList是不安全的,可能与这个相关,在多线程下不建议使用;以后可以再回头看看仔细琢磨一些实现细节。
(2)ArrayList的实现中大量调用了 Arrays.copyof()和System.arraycopy()方法,这两个方法之前内部实现了解的不多,后来看源码仔细琢磨了一下,在上面有对它们的详细注解分析过程,相信看过之后应该会比较清晰,按我的理解实际上就是自我复制与自我覆盖。
(3)ArrayList是基于数组的存储结构,所以支持随机读取,是通过下标索引查找指定元素,但是在插入删除的时候效率很低,因为要大量的复制移动数组元素。
(4)ArrayList支持迭代,内部数组存储允许重复元素,特别也允许null的元素,也支持null元素的查找,从上面的源码分析看出内部是将null元素与普通元素分成两种情况分别遍历查找。
ArrayList简介
(1) ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
(2) ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
(3) ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
ArrayList(JDK1.7)源码详细剖析注释
package java.util; /** * JDK1.7 * @author foolishbird_lmy * */ public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { //自动生成的序列版本号,主要用于版本的兼容问题 private static final long serialVersionUID = 8683452581122892189L; //默认的容量,用于每次数组的自动扩展 private static final int DEFAULT_CAPACITY = 10; //定义的一个默认空数组对象 private static final Object[] EMPTY_ELEMENTDATA = {}; //ArrayList是基于数组结构来实现的,该数组用来实际保存数据,transient这个关键字是声明改变量不能被序列化 private transient Object[] elementData; //当前集合中实际的元素的个数即大小 private int size; //带参数的构造函数,initialCapacity,初始化的容量即需要构造的List的大小 public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } //无参构造函数初始化,注意是根据默认大小限定为10,即你不传参数时也会构造大小为10的List public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; } /* *创建一个包含Collection类型的ArrayList,实际的过程是首先根据Collection中的元素复制一个数组 */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//返回包含此 collection 中所有元素的数组。 size = elementData.length;//数组的长度 if (elementData.getClass() != Object[].class)//判断是否为数组类型 elementData = Arrays.copyOf(elementData, size, Object[].class);//Arrays工具类,复制数组 } //将此 ArrayList 实例的容量调整为列表的当前大小,即根据当前的实际数组元素的长度设置容量 public void trimToSize() { modCount++; /*这个参数仔细查了一下,是父类AbstractList中定义了一个int型的属性:modCount,记录了ArrayList结构性变化的次数 包括:add()、remove()、addAll()、removeRange()及clear()方法。这些方法每调用一次,modCount的值就加1。 主要的作用就是在迭代的时候保持单线程的安全性;只要是容量发生变化这个参数就会自动随着变化 */ if (size < elementData.length) { elementData = Arrays.copyOf(elementData, size); } } /* 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数. DEFAULT_CAPACITY 默认的最小值10 EMPTY_ELEMENTDATA 默认为空 */ //这个方法的主要作用是确定当前集合的容量是否足够,minCapacity参数是所需的最小容量,如果小于则扩容 public void ensureCapacity(int minCapacity) { //三目运算,如果elementData为空,则minExpand=DEFAULT_CAPACITY=10,否则取0 int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY; //如果小于则扩容 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } //如果大于,说明容量足够 } //这个是1.7之后新加入的,主要是为了内部确保集合容量,与ensureCapacity相似,但是一个是public可以供外部使用,一个是private供内部使用 private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // 如果当前的实际容量小于需要的最小容量,则扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } // 这里定义了一个最大的数组长度,为什么会减8个字节了,我查了一下, // as the Array it self needs 8 bytes to stores the size 2,147,483,648 //暂且理解的意思是需要8个字节来存储数组的长度值,其实这个主要也是由虚拟机决定。 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /* 这个是扩容的实现;这里要注意一下,每次的扩容其实是到之前的1.5倍; oldCapacity + (oldCapacity >> 1) 实际上就是右移除2 结果是3/2oldCapacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; 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); } //用来判断是否超出数组最大范围 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } //返回ArrayList的实际大小 public int size() { return size; } //判断ArrayList是否为空 public boolean isEmpty() { return size == 0; } //判断是否包含某个元素 public boolean contains(Object o) { return indexOf(o) >= 0; } //从头开始查找某个元素,返回元素的索引值,注意,我们从源码中可以看到,是可以查找空值的。。并且没有找到是返回-1 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; } //反向从最后开始查找,与上面相反 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; } //执行克隆,注意这是一个浅克隆,并没有复制数组去创建一个新的,只是将一个新引用指向同一个对象而已。 public Object clone() { try { @SuppressWarnings("unchecked") ArrayList<E> v = (ArrayList<E>) 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(); } } //返回集合中元素以数组形式 public Object[] toArray() { return Arrays.copyOf(elementData, size); } //以指定T类型数组形式返回 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //如果数组a的大小<集合的大小,也就是元素的个数 if (a.length < size) // 返回一个新的T类型的数组,将集合中的元素全部拷贝过去 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); //否则数组a的大小>=集合的大小,则直接将集合中的数组全部拷贝到数组a中去 System.arraycopy(elementData, 0, a, 0, size); //注意:因为数组此时大小是大于集合中的元素的,拷贝之后会有剩余的空间,全部设置为null if (a.length > size) a[size] = null; return a; } //返回指定下标的元素 @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } //返回指定下标的元素 public E get(int 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) { //先扩容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //在指定的下标添加元素 public void add(int index, E element) { rangeCheckForAdd(index);//是否越界 //扩容 ensureCapacityInternal(size + 1); // Increments modCount!! //第一个elementData代表源数组,index代表从此下标开始截取,第二个elementData代表现在的目标数组,会将前面截取的数组从下标index + 1处开始覆盖 //例如数组{1,2,3,4,5} index=1 ,截取长度size - index为4,则第一个截取为{2,3,4,5},然后从index=2开始覆盖,得到{1,2,2,3,4,5,6}此时数组已经扩容了 //最后设置index=1处值即可,完成添加 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } //删除指定位置的元素并返回元素的值 public E remove(int index) { rangeCheck(index);//看下标是否越界 modCount++; E oldValue = elementData(index);//保存删除的元素 int numMoved = size - index - 1;//代表在index下标之后的全部元素的数量 if (numMoved > 0)//如果index不是最后一个元素 //采用复制数组的方式将index覆盖删除 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; //注意最后还要将最后一个元素设置为空,这是一个多余的重复元素 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; } //已经确认了存在要删除的元素,就直接找到删除,与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; } //将Collection容器中的元素全部以迭代的方式添加到此列表的尾部 public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray();//复制数组 int numNew = a.length;//长度 ensureCapacityInternal(size + numNew); // 扩容,准备添加到列表尾部 //取数组a,从0下标开始,长度为numNew,来覆盖数组elementData,下标从size开始,即从最后开始尾部添加 System.arraycopy(a, 0, elementData, size, numNew); size += numNew;//添加完后要相应长度增加 return numNew != 0;//如果参数中的容器元素为空,返回false,否则返回true } //从指定位置index处开始添加元素 public boolean addAll(int index, Collection<? extends E> c) { //与rangeCheck方法功能相似,也是判断下标是否越界,些许的区别是允许边界判断允许等于长度即从尾部开始添加,当然必须大于0啦 rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // 这三句与上面一样 /*我还是习惯用实例来分析,假设现在我们本来的列表为elementData={1,3,5,7,9} 参数index=1,a={2,4,6,8},则numMoved = size - index=size + numNew-index=8 注意这里已经扩容了,不然下面的复制操作会报 ArrayIndexOutOfBoundsException异常;即现在新的elementData={1,3,5,7,9,null,null,null,null} 开始逐步分析: 执行这句System.arraycopy(elementData, index, elementData, index + numNew,numMoved); (1)elementData中从index(包括index)取numMoved长度的数组,即{3,5,7,9,null,null,null,null} (2)elementData中从index + numNew = 5处(包括index + numNew)开始执行覆盖,即{1,3,5,7,9,3,5,7,9}后面的null舍弃. 执行System.arraycopy(a, 0, elementData, index, numNew); (1)a数组中从0开始取numNew长度数组,即{2,4,6,8} (2)elementData从index=1处(包括index)开始执行覆盖,即{1,2,4,6,8,3,5,7,9} 全部过程执行完毕,实现了从index插入数组。 */ int numMoved = size - index;//这是为了准备取index之后的元素 if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0;//如果参数中的容器元素为空,返回false,否则返回true } //删除指定位置范围内的元素,从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;//从这里可以看出其实集合中的实际容量并不止这些,还有将后面的闲置的空间设置为空,便于GC去回收 } size = newSize;//删除后要更新长度 } //根据源码的注释说明,这个方法并不会检查index为负数的情况,但是它会在访问数组之前,直接抛出ArrayIndexOutOfBoundsException异常 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } //主要是给add and addAll两个方法判断下标是否越界使用 private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } //主要用于抛出异常时定位详细信息 private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } //删除指定Collection中包含的元素,即只要是Collection中含有的元素,在列表中进行删除操作,会得到一个新的列表 public boolean removeAll(Collection<?> c) { return batchRemove(c, false); } //与上面的方法相反,仅仅保留Collection中含有的元素,相当于两个列表取交集 public boolean retainAll(Collection<?> c) { return batchRemove(c, true); } //这个内部方法只分析false过程,true过程相似 private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData;//获得列表中的数组 int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++)//遍历列表,如果参数complement传进来默认为fasle if (c.contains(elementData[r]) == complement)//变量列表中的所有元素是否存在与c中 elementData[w++] = elementData[r];//如果不存在,则将不存在的元素存放在elementData中前列,也就是从头开始覆盖掉与c中重复的元素只保留不同的元素 //这个其实就是找出两个列表中的不同元素放在原始列表的前段,相当于去除了相同的元素; //如果参数为true,则是找出两个列表中的相同元素放在原始列表的前段,相当于取出了交集元素; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { //finally中的功能实际上是通过复制覆盖截取列表前段已经找出来的不同元素 System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { // 主要是为了将列表后半段相同的元素置NULL,便于GC回收 for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w;//更新列表中的实际元素个数即长度 modified = true; } } return modified; } // java.io.Serializable的写入函数 // 将ArrayList的“容量,所有的元素值”都写入到输出流中 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ int expectedModCount = modCount;//记录标记 s.defaultWriteObject(); //写入“数组的容量” s.writeInt(size); // 写入列表中的每一个元素 for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } //这个变量我理解的是防止在写入输出流的同时,又在进行列表的删除或添加操作,保证单线程安全问题; if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } //与上面的对应,读取输出流 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { elementData = EMPTY_ELEMENTDATA;//默认为空 s.defaultReadObject(); s.readInt(); // 从输入流中读取列表容量 if (size > 0) { // 确保实际容量 ensureCapacityInternal(size); Object[] a = elementData; // 将输入流中的所有元素读取出来并赋值 for (int i=0; i<size; i++) { a[i] = s.readObject(); } } } //迭代器 public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } public ListIterator<E> listIterator() { return new ListItr(0); } public Iterator<E> iterator() { return new Itr(); } /*Itr内部类,实现了Iterator接口,主要是实现迭代器的功能,也就是设计模式适配器思想,用于迭代出列表中的全部元素,*/ private class Itr implements Iterator<E> { int cursor; // 默认的返回迭代的下一个元素索引 int lastRet = -1; // 默认的返回最后一个元素的索引,如果数组为空直接返回-1 int expectedModCount = modCount; //是否还存在下一个元素,即是否迭代到列表尾部 public boolean hasNext() { return cursor != size;//迭代到尾部返回true,否则返回false } //获取下一个元素值 @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;//记住指向下一个元素索引,便于下次迭代 return (E) elementData[lastRet = i];//更新lastRet值 } //从尾部开始删除 public void remove() { if (lastRet < 0)//其实就是-1,则列表为空 throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet);//从最后开始删除 cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } /*ListItr内部类,继承了Itr类,实现了迭代器功能,主要是继承了ListIterator接口 系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。 ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。 长度为 n 的列表的迭代器有 n+1 个可能的指针位置 */ private class ListItr extends Itr implements ListIterator<E> { //带参数的构造函数 ListItr(int index) { super(); cursor = index; } /*如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。 换句话说,如果 previous 返回一个元素而不是抛出异常,则返回 true)。 其实就是确定当前迭代出的元素是否有前任元素,当迭代出的是第一个元素时, */ public boolean hasPrevious() { return cursor != 0; } //返回下一个元素的索引,如果迭代到列表的尾部,则返回列表的大小 public int nextIndex() { return cursor; } //返回当前迭代元素的 public int previousIndex() { return cursor - 1; } @SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; } public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } //返回一个新的列表,范围是fromIndex到toIndex public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); //直接用构造函数构建 return new SubList(this, 0, fromIndex, toIndex); } //检查下标的范围是否越界 static void subListRangeCheck(int fromIndex, int toIndex, int size) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > size) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } /* SubList内部类,继承了AbstractList抽象类,AbstractList实现了AbstractCollection,适配器设计模式; 实现了RandomAccess接口支持随机访问; */ 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;//初始化为要截取列表的开始下标,这里假定从原始列表的头开始算,初始偏移量为0 this.size = toIndex - fromIndex;//截取的长度 this.modCount = ArrayList.this.modCount; } //设置指定下标的值 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 E get(int index) { rangeCheck(index); checkForComodification(); return ArrayList.this.elementData(offset + index); } //获取当前列表长度 public int size() { checkForComodification(); return this.size; } //在指定位置添加元素 public void add(int index, E e) { rangeCheckForAdd(index); checkForComodification(); parent.add(parentOffset + index, e); this.modCount = parent.modCount; this.size++; } //删除指定下标的元素 public E remove(int index) { rangeCheck(index); checkForComodification(); E result = parent.remove(parentOffset + index); this.modCount = parent.modCount; this.size--; return result; } //删除指定范围内的元素 protected void removeRange(int fromIndex, int toIndex) { checkForComodification(); //调用的是AbstractList中的removeRange方法,采用迭代逐一删除元素 parent.removeRange(parentOffset + fromIndex, parentOffset + toIndex); this.modCount = parent.modCount; this.size -= toIndex - fromIndex; } //将c中的元素全部添加到当前列表的尾部 public boolean addAll(Collection<? extends E> c) { return addAll(this.size, c); } //将c中的元素全部添加到当前列表的指定index位置 public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); int cSize = c.size(); if (cSize==0) return false;//为null直接返回 checkForComodification(); parent.addAll(parentOffset + index, c); this.modCount = parent.modCount; this.size += cSize; return true; } public Iterator<E> iterator() { return listIterator(); } public ListIterator<E> listIterator(final int index) { checkForComodification(); rangeCheckForAdd(index); final int offset = this.offset; return new ListIterator<E>() { int cursor = index; int lastRet = -1; int expectedModCount = ArrayList.this.modCount; public boolean hasNext() { return cursor != SubList.this.size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= SubList.this.size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (offset + i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[offset + (lastRet = i)]; } public boolean hasPrevious() { return cursor != 0; } @SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (offset + i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[offset + (lastRet = i)]; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { SubList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = ArrayList.this.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(offset + lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; SubList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = ArrayList.this.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (expectedModCount != ArrayList.this.modCount) throw new ConcurrentModificationException(); } }; } //返回原始列表范围的部分列表,从fromIndex(包括)开始,到toIndex(不包括) public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, offset, fromIndex, toIndex); } private void rangeCheck(int index) { if (index < 0 || index >= this.size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private void rangeCheckForAdd(int index) { if (index < 0 || index > this.size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+this.size; } private void checkForComodification() { if (ArrayList.this.modCount != this.modCount) throw new ConcurrentModificationException(); } } }
还是总结一下
(1)其实源码里面还是有一些代码不太懂,例如modCount变量,只知道是与线程安全相关,ArrayList是不安全的,可能与这个相关,在多线程下不建议使用;以后可以再回头看看仔细琢磨一些实现细节。
(2)ArrayList的实现中大量调用了 Arrays.copyof()和System.arraycopy()方法,这两个方法之前内部实现了解的不多,后来看源码仔细琢磨了一下,在上面有对它们的详细注解分析过程,相信看过之后应该会比较清晰,按我的理解实际上就是自我复制与自我覆盖。
(3)ArrayList是基于数组的存储结构,所以支持随机读取,是通过下标索引查找指定元素,但是在插入删除的时候效率很低,因为要大量的复制移动数组元素。
(4)ArrayList支持迭代,内部数组存储允许重复元素,特别也允许null的元素,也支持null元素的查找,从上面的源码分析看出内部是将null元素与普通元素分成两种情况分别遍历查找。
相关文章推荐
- #java读书笔记#集合框架3
- 多态
- Struts2中自定义类型转换器
- java IO流
- Spring MVC 中 HandlerInterceptorAdapter的使用
- Java中HashMap详解
- javaDAY5
- 个人对设计模式的理解-->建造者模式
- HashMapUtil java项目中缓存的使用
- 用Java 编一段代码,实现在控制台输入一组数字后,排序后在控制台输出
- struts1.0 struts标签
- java中商业数据计算时用到的类BigDecimal和DecimalFormat
- 1---------java调用NLPIR(ICTCLAS2016)实现分词功能
- 接口与抽象类
- 【小笨鸟看JDK1.7集合源码之一】JAVA集合整体框架
- Spring-Security
- Spring MVC 和 Struts2 的区别?
- Ubuntu下安装了java但启动eclipse报错说没装java
- JAVA使用JDBC连接MySQL数据库
- Spring IOC核心源码学习