ArrayList类的注解阅读


  1. /**
  2. * Resizable-array implementation of the <tt>List</tt> interface. Implements
  3. * all optional list operations, and permits all elements, including
  4. * <tt>null</tt>. In addition to implementing the <tt>List</tt> interface,
  5. * this class provides methods to manipulate the size of the array that is
  6. * used internally to store the list. (This class is roughly equivalent to
  7. * <tt>Vector</tt>, except that it is unsynchronized.)
  8. 这是一个实现了List接口的可变长度的数组。实现了list接口中的所有方法,允许存放所有的元素,包括null。除了实现list接口,该类还提供了一些方法来操作数组的大小,此数组被用来存储list的数据。(这个类和vector大致相当,除了它是线程不安全的)
  • ArrayList底层实现是数组,可存放重复数据,包括null,线程不安全
  1. *
  2. * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
  3. * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
  4. * time. The <tt>add</tt> operation runs in <i>amortized constant time</i>,
  5. * that is, adding n elements requires O(n) time. All of the other operations
  6. * run in linear time (roughly speaking). The constant factor is low compared
  7. * to that for the <tt>LinkedList</tt> implementation.
  8. *
  9. size(),isEmpty(),get(),set()方法使用的一个恒定时间(一个方法具有恒定的执行时间的,也就是代码不会因为问题规模n的变化而发生变化,时间复杂度记为O(1))。add操作花费恒定分摊时间,即插入n个元素需要on)的时间。 粗略的来说所有其他操作都以线性时间运行。(即这些操作与元素的个数成线性关系,操作的时间复杂度on))。这些操作与LinkedList实现相比,常数因子较低。
  • 底层为数组结构,相对于LinkedList效率较高
  1. * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>. The capacity is
  2. * the size of the array used to store the elements in the list. It is always
  3. * at least as large as the list size. As elements are added to an ArrayList,
  4. * its capacity grows automatically. The details of the growth policy are not
  5. * specified beyond the fact that adding an element has constant amortized
  6. * time cost.
  7. *
  8. 每个ArrayList的实例对象都有一个容量(capacity)。这个容量就是这个list中用来存储元素的数组的大小。它至少和list的大小一样大。当有元素被增加到集合中时,它的容量会自动增加。除了要求添加一个元素的效率为“恒定分摊时间”,对于具体实现的细节没有特别的要求。
  9. * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
  10. * before adding a large number of elements using the <tt>ensureCapacity</tt>
  11. * operation. This may reduce the amount of incremental reallocation.
  12. 在大批量插入元素前,使用ensureCapacity()方法来增加集合的容量。这或许能够减少扩容增加量的大小。
  1. * <p><strong>Note that this implementation is not synchronized.</strong>
  2. * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
  3. * and at least one of the threads modifies the list structurally, it
  4. * <i>must</i> be synchronized externally. (A structural modification is
  5. * any operation that adds or deletes one or more elements, or explicitly
  6. * resizes the backing array; merely setting the value of an element is not
  7. * a structural modification.) This is typically accomplished by
  8. * synchronizing on some object that naturally encapsulates the list.
  9. *
  10. 注意这个实现类是非同步的。如果有多个线程同时操作一个ArrayList的实例。然后,至少有一个线程修改了list的结构,就必须在外部保证它的线程同步。(结构修改指的是增加或者删除一个或多个映射;如果仅仅是更改已经存在的
  11. keyvalue值,不算做结构修改)。这通常需要在一个被封装好的list对象上,使用同步进行操作。
  • ArrayList是非同步的,线程不安全的
  1. * If no such object exists, the list should be "wrapped" using the
  2. * {@link Collections#synchronizedList Collections.synchronizedList}
  3. * method. This is best done at creation time, to prevent accidental
  4. * unsynchronized access to the list:<pre>
  5. * List list = Collections.synchronizedList(new ArrayList(...));</pre>
  6. *
  7. 如果没有这样的对象存在,那么就需要使用Collections.synchronizedList方法来包装这个list对象,而且最好是在创建对象的时候就进行包装,这是为了预防对这个list对象进行一些线程不同步的操作。举个例子:List list = Collections.synchronizedList(new ArrayList(...));
  • 尽管有一个线程安全的类Vector和ArrayList结构类似,但是我们在需要保证线程安全时依然不会使用Vector这个类(过时的类),而是使用 Collections.synchronizedList()方法来包装得到一个线程安全的list对象。
  1. * <p><a name="fail-fast">
  2. * The iterators returned by this class's {@link #iterator() iterator} and
  3. * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
  4. * if the list is structurally modified at any time after the iterator is
  5. * created, in any way except through the iterator's own
  6. * {@link ListIterator#remove() remove} or
  7. * {@link ListIterator#add(Object) add} methods, the iterator will throw a
  8. * {@link ConcurrentModificationException}. Thus, in the face of
  9. * concurrent modification, the iterator fails quickly and cleanly, rather
  10. * than risking arbitrary, non-deterministic behavior at an undetermined
  11. * time in the future.
  12. *
  13. 该类的集合视图方法返回的迭代器是fail-fast机制的:在迭代器被创建后,如果list对象被结构化修改后,无论在何时,使用何种方法(除了迭代器本身的remove方法和add方法)来修改它,都会抛出ConcurrentModificationException.因此,面对并发修改操作时,迭代器会迅速且清晰地报错.而不是冒着在不确定的时间做不确定的操作的风险.
  • fail-fast,它是Java集合中的一种错误检测机制。某个线程在对collection进行迭代时,不允许其他线程对该collection进行结构上的修改。否则程序就会抛出ConcurrentModificationException 异常。快速终止操作

  1. * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
  2. * as it is, generally speaking, impossible to make any hard guarantees in the
  3. * presence of unsynchronized concurrent modification. Fail-fast iterators
  4. * throw {@code ConcurrentModificationException} on a best-effort basis.
  5. * Therefore, it would be wrong to write a program that depended on this
  6. * exception for its correctness: <i>the fail-fast behavior of iterators
  7. * should be used only to detect bugs.</i>
  8. 注意,迭代器的fail-fast行为是不能保证的.一般来说,保证非同步的同步操作是不太可能的.在最优基础上,Fail-fast迭代器会抛出ConcurrentModificationException.因此,写一个为了自身正确性而依赖于这个异常的程序是不对的.迭代器的fail-fast行为应该只是用来检测bug而已.
  • 我们要主动封装list以便进行同步操作,程序要要避免此异常而不是使用此异常

ArrayList类的定义

  1. public class ArrayList<E> extends AbstractList<E>
  2. implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承的类

    AbstractList:抽象类,只需知道此类是List接口的简单通用实现

  • 实现的接口

    List:不多说了


    RandomAccess:(标记接口)代表支持随机访问

    Cloneable:(标记接口)代表 Object.clone() 方法可以合法地对该类实例进行按字段复制。(没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常)

    java.io.Serializable(标记接口)

属性的定义

  1. protected transient int modCount = 0;
  • 这是父类AbstractList的一个属性 :用于记录列表结构被修改的次数。每次列表结构被修改都会modCount++

    为什么要记录此数据呢?

    在线程不安全的集合中,正如上面所说:迭代器采用了fail-fast机制。而fail-fast机制触发原理就是比对expectedModCount 和 modCount 是否相等,不相等就报ConcurrentModificationException异常

    此处不理解没关系,后面会讲迭代器方法的源码时,就会明白了
  1. /**
  2. * Default initial capacity.
  3. * 初始默认容量 为 10
  4. */
  5. private static final int DEFAULT_CAPACITY = 10;
  1. /**
  2. * Shared empty array instance used for empty instances.
  3. *
  4. * 指定该ArrayList容量为0时,返回该空数组。
  5. */
  6. private static final Object[] EMPTY_ELEMENTDATA = {};
  1. /**
  2. * Shared empty array instance used for default sized empty instances. We
  3. * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
  4. * first element is added.
  5. *
  6. * 用于默认大小的空实例的共享空数组实例。
  7. * 这个空数组的实例用来给无参构造使用。当调用无参构造方法,返回的是该数组。
  8. * 将此与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要增加多少容量。
  9. */
  10. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • EMPTY_ELEMENTDATA 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA都是表示空数组实例

    区别在于:

    EMPTY_ELEMENTDATA 是用户指定初试容量为0时 使用它

    DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是默认创建初始容量为10的空数组,被无参构造器使用

    将此与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要增加多少容量
  1. /**
  2. * The array buffer into which the elements of the ArrayList are stored.
  3. * The capacity of the ArrayList is the length of this array buffer. Any
  4. * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  5. * will be expanded to DEFAULT_CAPACITY when the first element is added.
  6. *
  7. * 存储ArrayList元素的数组缓冲区
  8. * ArrayList的容量(capacity)就是是此数组缓冲区的长度。
  9. * 声明为transient 不会被序列化
  10. * 非私有 是为了方便内部类调用
  11. */
  12. transient Object[] elementData; // non-private to simplify nested class access
  • 该值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入ArrayList中时, 数组将扩容至DEFAULT_CAPACITY。这也印证了为什么区分EMPTY_ELEMENTDATA,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  1. /**
  2. * The size of the ArrayList (the number of elements it contains).
  3. *
  4. * List中元素的个数
  5. */
  6. private int size;
  • 仅仅表示 该list包含的元素的个数,和数组容量没有任何关系

这里提一点:前面提到size()方法时间复杂度为O(1),是因为它将size存储起来了,牺牲了空间提高了效率。

ArrayList构造器

ArrayList有三个构造器

  1. 创建一个指定存储容量的空序列
  2. public ArrayList(int initialCapacity) {
  3. if (initialCapacity > 0) {
  4. this.elementData = new Object[initialCapacity];
  5. } else if (initialCapacity == 0) {
  6. this.elementData = EMPTY_ELEMENTDATA;
  7. } else {
  8. throw new IllegalArgumentException("Illegal Capacity: "+
  9. initialCapacity);
  10. }
  11. }
  • 指定的initialCapacity

    >0时,创建的序列容量为initialCapacity

    ==0时,创建的是 EMPTY_ELEMENTDATA

    <0时,会报异常
  1. 无参构造,创建一个初始容量为10 的空序列
  2. public ArrayList() {
  3. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  4. }
  • 此处使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA

  1. 遵循集合的约定 提供 一个可将Collection转换为ArrayList的构造器
  2. 这些元素是按照该 Collection 的迭代器返回它们的顺序排列的。
  3. public ArrayList(Collection<? extends E> c) {
  4. elementData = c.toArray();
  5. if ((size = elementData.length) != 0) {
  6. // c.toArray might (incorrectly) not return Object[] (see 6260652)
  7. if (elementData.getClass() != Object[].class)
  8. elementData = Arrays.copyOf(elementData, size, Object[].class);
  9. } else {
  10. // replace with empty array.
  11. this.elementData = EMPTY_ELEMENTDATA;
  12. }
  13. }
  • 注意:toArray的方法返回的类型不一定是Object[] 这是jDK的bug,两个类之间有继承关系时,JDK允许向上转型(子类赋值给父类)而 向下转型(父类赋值给子类)是不允许的。为了解决这个问题需要检验运行时类型使用Arrays.copyOf将其转为Object[]类型

核心方法


  1. /**
  2. * Trims the capacity of this <tt>ArrayList</tt> instance to be the
  3. * list's current size. An application can use this operation to minimize
  4. * the storage of an <tt>ArrayList</tt> instance.
  5. *
  6. * 将ArrayList的容量设置为当前size的大小,应用可以使用此方法最小化实例的存储空间
  7. *
  8. */
  9. public void trimToSize() {
  10. modCount++;
  11. if (size < elementData.length) {
  12. elementData = (size == 0)
  13. ? EMPTY_ELEMENTDATA
  14. : Arrays.copyOf(elementData, size);
  15. }
  16. }
  • 注意:首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作。此操作修改了列表结构,所以modCount++;

  1. /**
  2. * Increases the capacity of this <tt>ArrayList</tt> instance, if
  3. * necessary, to ensure that it can hold at least the number of elements
  4. * specified by the minimum capacity argument.
  5. *
  6. * 如有必要,增加此ArrayList实例的容量,以确保它至少可以容纳由minCapacity参数指定的元
  7. * 素数。
  8. *
  9. * @param minCapacity the desired minimum capacity
  10. */
  11. public void ensureCapacity(int minCapacity) {
  12. int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
  13. // any size if not default element table
  14. ? 0
  15. // larger than default for default empty table. It's already
  16. // supposed to be at default size.
  17. : DEFAULT_CAPACITY;
  18. if (minCapacity > minExpand) {
  19. ensureExplicitCapacity(minCapacity);
  20. }
  21. }
  22. private void ensureCapacityInternal(int minCapacity) {
  23. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  24. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  25. }
  26. ensureExplicitCapacity(minCapacity);
  27. }
  • ensureCapacity方法中,minExpand 表示最小扩容量, minCapacity表示最小容量,在这里分了两种情况

    此实例 是默认大小的ArrayList,最小扩容量为DEFAULT_CAPACITY 否则为 0;然后比较minCapacity 和 minExpand,如果期望的最小容量比最小扩容量小就不扩容,反之使用minCapacity进行扩容

ensureCapacityInternal方法,数组容量检查,不够时则进行扩容,只供类内部使用,例如add(),addAll()等方法时会调用此方法进行容量检验,此时minCapacity 通常为size+n

  1. private void ensureExplicitCapacity(int minCapacity) {
  2. modCount++;
  3. // overflow-conscious code
  4. // 只有最小容量比当前容量大时才会进行扩容
  5. if (minCapacity - elementData.length > 0)
  6. grow(minCapacity);
  7. }
  8. /**
  9. * The maximum size of array to allocate.
  10. * Some VMs reserve some header words in an array.
  11. * Attempts to allocate larger arrays may result in
  12. * OutOfMemoryError: Requested array size exceeds VM limit
  13. *
  14. * 最大存储容量
  15. */
  16. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  17. /**
  18. * Increases the capacity to ensure that it can hold at least the
  19. * number of elements specified by the minimum capacity argument.
  20. *
  21. * @param minCapacity the desired minimum capacity
  22. */
  23. private void grow(int minCapacity) {
  24. // overflow-conscious code
  25. int oldCapacity = elementData.length;
  26. // 先预先扩容1.5倍
  27. int newCapacity = oldCapacity + (oldCapacity >> 1);
  28. if (newCapacity - minCapacity < 0)
  29. newCapacity = minCapacity;
  30. if (newCapacity - MAX_ARRAY_SIZE > 0)
  31. // 主要判断 预期最小容量 minCapacity 是否大于 MAX_ARRAY_SIZE
  32. newCapacity = hugeCapacity(minCapacity);
  33. // minCapacity is usually close to size, so this is a win:
  34. elementData = Arrays.copyOf(elementData, newCapacity);
  35. }
  36. private static int hugeCapacity(int minCapacity) {
  37. if (minCapacity < 0) // overflow
  38. throw new OutOfMemoryError();
  39. return (minCapacity > MAX_ARRAY_SIZE) ?
  40. Integer.MAX_VALUE :
  41. MAX_ARRAY_SIZE;
  42. }

总结:

  1. 只有最小容量比当前容量大时才会进行扩容;
  2. 扩容操作时,会预先把容量扩容至自身容量的1.5倍(预扩容)(使用的是oldCapacity + (oldCapacity >> 1)),然后于需要的最小容量minCapacity进行比较,选其最大值;
  3. 最终需要的容量会判断是否超过数组最大容量MAX_ARRAY_SIZE,1.没有超过 ——> 生成新的容量数组;2.超过了 ——> 会进行判断(1.是需要的最小容量超过了MAX_ARRAY_SIZE ——> 最终容量设为Integer.MAX_VALUE; 2.还是预扩容超过了MAX_ARRAY_SIZE ——> 最终容量设为MAX_ARRAY_SIZE) ——> 生成新的容量数组;
  4. 使用最大容量MAX_ARRAY_SIZE时,要注意因为某些VM会在数组中保留一些头字,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
  5. minCapacity<0时也会触发MAX_ARRAY_SIZE,但这种情况在我的认知下不会发生,可能是严谨的做法,安全检查;

普通方法


  1. public boolean contains(Object o) {
  2. // 借用indexOf的方法看是否存在
  3. return indexOf(o) >= 0;
  4. }
  5. // 实质就是遍历数组,使用Object的equals方法,返回-1为不存在此元素,lastIndexOf()方法就是反向遍历
  6. public int indexOf(Object o) {
  7. if (o == null) {
  8. for (int i = 0; i < size; i++)
  9. if (elementData[i]==null)
  10. return i;
  11. } else {
  12. for (int i = 0; i < size; i++)
  13. if (o.equals(elementData[i]))
  14. return i;
  15. }
  16. return -1;
  17. }
  18. public boolean add(E e) {
  19. // 检验是否需要扩容
  20. ensureCapacityInternal(size + 1); // Increments modCount!!
  21. // 先在index=size的位置赋值e,再将ArrayList的size增加一位
  22. elementData[size++] = e;
  23. return true;
  24. }
  25. /**
  26. * Inserts the specified element at the specified position in this
  27. * list. Shifts the element currently at that position (if any) and
  28. * any subsequent elements to the right (adds one to their indices).
  29. *
  30. * @param index index at which the specified element is to be inserted
  31. * @param element element to be inserted
  32. * @throws IndexOutOfBoundsException {@inheritDoc}
  33. */
  34. public void add(int index, E element) {
  35. rangeCheckForAdd(index);
  36. ensureCapacityInternal(size + 1); // Increments modCount!!
  37. System.arraycopy(elementData, index, elementData, index + 1,
  38. size - index);
  39. elementData[index] = element;
  40. size++;
  41. }

总结:

  1. add()一个参数直接加在数组最后
  2. add(index, element) 使用System.arraycopy()将index的位置空出来,将值赋值过去。System.arraycopy为 JVM 内部固有方法,它通过手工编写汇编或其他优化方法来进行 Java 数组拷贝,这种方式比起直接在 Java 上进行 for 循环或 clone 是更加高效的。数组越大体现地越明显。
  1. /**
  2. * Removes the element at the specified position in this list.
  3. * Shifts any subsequent elements to the left (subtracts one from their
  4. * indices).
  5. *
  6. * @param index the index of the element to be removed
  7. * @return the element that was removed from the list
  8. * @throws IndexOutOfBoundsException {@inheritDoc}
  9. */
  10. public E remove(int index) {
  11. rangeCheck(index);
  12. modCount++;
  13. E oldValue = elementData(index);
  14. int numMoved = size - index - 1;
  15. if (numMoved > 0)
  16. System.arraycopy(elementData, index+1, elementData, index,
  17. numMoved);
  18. // 将数组最后一位 置 null,等待垃圾回收机制来回收
  19. elementData[--size] = null; // clear to let GC do its work
  20. return oldValue;
  21. }
  22. public List<E> subList(int fromIndex, int toIndex) {
  23. subListRangeCheck(fromIndex, toIndex, size);
  24. return new SubList(this, 0, fromIndex, toIndex);
  25. }
  26. private class SubList extends AbstractList<E> implements RandomAccess {

迭代器(iterator&ListIterator)实现

ArrayList中的迭代器实现对AbstractList中的迭代器进行了优化

  1. /**
  2. * Returns an iterator over the elements in this list in proper sequence.
  3. *
  4. * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
  5. *
  6. * 按原有list的顺序返回一个迭代器,遵循fail-fast机制。
  7. *
  8. *
  9. * @return an iterator over the elements in this list in proper sequence
  10. */
  11. public Iterator<E> iterator() {
  12. return new Itr();
  13. }
  14. /**
  15. * An optimized version of AbstractList.Itr
  16. */
  17. private class Itr implements Iterator<E> {
  18. // 后游标:指向下一个元素,等于下一个元素的索引值
  19. int cursor; // index of next element to return
  20. // 前游标:指向当前元素,等于当前元素索引值,-1代表在最开始,还未指向元素
  21. int lastRet = -1; // index of last element returned; -1 if no such
  22. // 将预期修改次数 和 实际修改次数 保持相等
  23. int expectedModCount = modCount;
  24. // 是否有下一个元素
  25. public boolean hasNext() {
  26. return cursor != size;
  27. }
  28. @SuppressWarnings("unchecked")
  29. public E next() {
  30. // 检查 预期修改次数 和 实际修改次数 是否相等——>数据结构是否改变
  31. checkForComodification();
  32. int i = cursor;
  33. if (i >= size)
  34. throw new NoSuchElementException();
  35. Object[] elementData = ArrayList.this.elementData;
  36. if (i >= elementData.length)
  37. throw new ConcurrentModificationException();
  38. cursor = i + 1; // 后游标右移
  39. return (E) elementData[lastRet = i];
  40. }
  41. public void remove() {
  42. if (lastRet < 0)
  43. throw new IllegalStateException();
  44. checkForComodification();
  45. try {
  46. // 调用ArrayList的remove
  47. ArrayList.this.remove(lastRet);
  48. // remove之后 后游标左移
  49. cursor = lastRet;
  50. // 重制前游标
  51. lastRet = -1;
  52. // 并且会使预期修改次数 和 实际修改次数 保持相等
  53. expectedModCount = modCount;
  54. } catch (IndexOutOfBoundsException ex) {
  55. throw new ConcurrentModificationException();
  56. }
  57. }
  58. // 检查 实际修改次数 和 预期修改次数是否相等
  59. final void checkForComodification() {
  60. if (modCount != expectedModCount)
  61. throw new ConcurrentModificationException();
  62. }
  63. }
  • 总结:

    使用迭代器便利的时候,remove元素时,要使用Iterator.remove(),虽然其本质也是调用ArrayList的remove()的方法,只是为了使 modCount,expectedModCount 保持相等,否则会报ConcurrentModificationException()异常
  1. /**
  2. * Returns a list iterator over the elements in this list (in proper
  3. * sequence), starting at the specified position in the list.
  4. * The specified index indicates the first element that would be
  5. * returned by an initial call to {@link ListIterator#next next}.
  6. * An initial call to {@link ListIterator#previous previous} would
  7. * return the element with the specified index minus one.
  8. *
  9. * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
  10. *
  11. * @throws IndexOutOfBoundsException {@inheritDoc}
  12. */
  13. public ListIterator<E> listIterator(int index) {
  14. if (index < 0 || index > size)
  15. throw new IndexOutOfBoundsException("Index: "+index);
  16. return new ListItr(index);
  17. }
  18. /**
  19. * Returns a list iterator over the elements in this list (in proper
  20. * sequence).
  21. *
  22. * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
  23. *
  24. * @see #listIterator(int)
  25. */
  26. public ListIterator<E> listIterator() {
  27. return new ListItr(0);
  28. }
  29. /**
  30. * An optimized version of AbstractList.ListItr
  31. */
  32. private class ListItr extends Itr implements ListIterator<E> {
  33. ListItr(int index) {
  34. super();
  35. cursor = index;
  36. }
  37. public boolean hasPrevious() {
  38. return cursor != 0;
  39. }
  40. public int nextIndex() {
  41. return cursor;
  42. }
  43. public int previousIndex() {
  44. return cursor - 1;
  45. }
  46. @SuppressWarnings("unchecked")
  47. public E previous() {
  48. checkForComodification();
  49. int i = cursor - 1;
  50. if (i < 0)
  51. throw new NoSuchElementException();
  52. Object[] elementData = ArrayList.this.elementData;
  53. if (i >= elementData.length)
  54. throw new ConcurrentModificationException();
  55. cursor = i;
  56. return (E) elementData[lastRet = i];
  57. }
  58. checkForComodification();
  59. int i = cursor;
  60. if (i >= size)
  61. throw new NoSuchElementException();
  62. Object[] elementData = ArrayList.this.elementData;
  63. if (i >= elementData.length)
  64. throw new ConcurrentModificationException();
  65. cursor = i + 1; // 后游标右移
  66. return (E) elementData[lastRet = i];
  67. public void set(E e) {
  68. if (lastRet < 0)
  69. throw new IllegalStateException();
  70. checkForComodification();
  71. try {
  72. ArrayList.this.set(lastRet, e);
  73. } catch (IndexOutOfBoundsException ex) {
  74. throw new ConcurrentModificationException();
  75. }
  76. }
  77. public void add(E e) {
  78. checkForComodification();
  79. try {
  80. int i = cursor;
  81. // 在当前元素的后面加入此元素
  82. ArrayList.this.add(i, e);
  83. cursor = i + 1;
  84. lastRet = -1;
  85. // add 操作会导致 modCount++,所以这边要保持相等
  86. expectedModCount = modCount;
  87. } catch (IndexOutOfBoundsException ex) {
  88. throw new ConcurrentModificationException();
  89. }
  90. }
  91. }
  • remove和add操作成功后 lastRet都会重新赋值为-1,并且会执行expectedModCount = modCount操作,以防ConcurrentModificationException;

  • ListItr继承于Itr,增加了previous()等一些方法,最大不同是游标cursor可以向前移动了。

  • 注意:执行过next()方法后再执行previous(),当前元素并没有改变(lastRet没有变),只是cursor进行了了改变,不要进行常规思考 previous()操作就是当前元素向前移动,next()就是当前元素向后移动,准确来说是cursor进行前后移动,进行previous()操作时 lastRet始终等于cursor,next()操作时cursor始终比lastRet大1

最后声明

  源码版本为JDK1.8,只是对日常使用的基本操作的源码进行了分析,对于1.8的新特性并没有涉及,等将主要集合类源码分析完后,会专门出一篇分析一下1.8中集合的新特性;

  有建议或着问题的,请在文末留言,本人水平有限,有错误或理解偏差,还请各位多多指导和见谅,如若转载,请表明出处;

ArrayList源码阅读笔记(1.8)的更多相关文章

  1. ArrayList源码阅读笔记(基于JDk1.8)

    关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...

  2. ArrayList源码阅读笔记

    ArrayList ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAcc ...

  3. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  4. CopyOnWriteArrayList源码阅读笔记

    简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...

  5. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  6. HashMap源码阅读笔记

    HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述   HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...

  7. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  8. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  9. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

随机推荐

  1. windows下复制文件报错“文件名对目标文件夹可能过长 。您可以缩短文件名并重试,或者......”

    我将一个路径下文件夹复制到另一个路径下时,出现了报错,报错图片如下: 然后查资料发现: 1.文件名长度最大为255个英文字符,其中包括文件扩展名在内.一个汉字相当于两个英文字符.2.文件的全路径名长度 ...

  2. log4cplus在Linux下编译及使用

    log4cplus第一次在windows下使用的时候很快就完成了,最近在Linux下尝试使用时遇到了不少问题,主要原因是对Linux的编译连接不熟悉,以下就记录安装使用的过程,希望对需要的人有所帮助. ...

  3. Leetcode: The Maze III(Unsolved Lock Problem)

    There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolli ...

  4. asp.net 经常用到需要判断文本框是否输入的数字是小数,有无正负,几位小数,可以封装一起判断

    /// <summary> /// 判断是否为小数点数字且带符号 /// </summary> /// <param name="symbol"> ...

  5. 【转载】SVN使用教程总结

    SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subversion是什么? ...

  6. 【转】OJ提交时G++与C++的区别

    关于G++ 首先更正一个概念,C++是一门计算机编程语言,G++不是语言,是一款编译器中编译C++程序的命令而已.那么他们之间的区别是什么? 在提交题目中的语言选项里,G++和C++都代表编译的方式. ...

  7. WCF 基础框架

    WCF 基础框架: 1,契约:契约书一语个服务公共接口的一部分,一个服务的契约定义了服务端公开的方法,使用的传递协议,可访问的地址,传输的消息格式等内容,主要包括数据契约,消息契约,服务契约等. 2, ...

  8. Mysql 聚合函数返回NULL

    [1]聚合函数返回NULL 当where条件不满足时,聚合函数sum().avg()的返回值为NULL. (1)源数据表 (2)如下SQL语句 SELECT sClass, COUNT(*) AS t ...

  9. Flask实战-留言板-使用Faker生成虚拟数据

    使用Faker生成虚拟数据 创建虚拟数据是编写Web程序时的常见需求.在简单的场景下,我们可以手动创建一些虚拟数据,但更方便的选择是使用第三方库实现.流行的python虚拟数据生成工具有Mimesis ...

  10. JAVA课堂测试之查找字母和单词出现次数、频率

    代码如下:没有加注释,自己研究吧. import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;i ...