前言 在日常编程中,ArrayList是使用最多的列表。在上篇文章 AbstractCollection学习 的学习中,我们可以从java基础集合框架图
中得知:ArrayList继承了AbstractList
,并实现了List
接口。而其中 AbstractList 则继承了AbstractCollection
。
内部数据结构 数据结构 1 2 3 4 5 6 7 8 9 10 public abstract class AbstractList <E > extends AbstractCollection <E > implements List <E > { protected transient int modCount = 0 ; private class Itr implements Iterator <E > {} private class ListItr extends Itr implements ListIterator <E > {} }
AbstractList继承了AbstractCollection抽象类,并实现了List接口。关于AbstractCollection已在另篇文章 讲解。关于List接口,在下文有简述。AbstractList中唯一的一个属性为modCount
,表示集合被修改的次数。在AbstractList的子类中,凡是涉及到修改列表的内部数据结构的方法,都是修改modCount
的值。
List 源码分析
数据结构 1 2 3 public interface List <E > extends Collection <E > { }
由类的声明可知,List接口继承了java集合框架的超类 Collection,该类中定义了列表的所有基本操作。
基本方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public interface List <E > extends Collection <E > { boolean add (E e) ; void add (int index, E element) ; boolean addAll (Collection<? extends E> c) ; boolean addAll (int index, Collection<? extends E> c) ; E set (int index, E element) ; E remove (int index) ; boolean remove (Object o) ; boolean removeAll (Collection<?> c) ; void clear () ; E get (int index) ; boolean containsAll (Collection<?> c) ; int indexOf (Object o) ; int lastIndexOf (Object o) ; int size () ; boolean isEmpty () ; boolean contains (Object o) ; Object[] toArray(); <T> T[] toArray(T[] a); boolean retainAll (Collection<?> c) ; boolean equals (Object o) ; int hashCode () ; List<E> subList (int fromIndex, int toIndex) ; default void sort (Comparator<? super E> c) { Object[] a = this .toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this .listIterator(); for (Object e : a) { i.next(); i.set((E) e); } } Iterator<E> iterator () ; ListIterator<E> listIterator () ; ListIterator<E> listIterator (int index) ; }
由List的源码可知,在接口List中,定义了列表的所有基本操作,比如常见的增删改查
。还有用于获取遍历列表的迭代器方法。具体实现逻辑,需有子类根据自身需求去实现。
添加方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean add (E e) { add(size(), e); return true ; } public boolean addAll (int index, Collection<? extends E> c) { rangeCheckForAdd(index); boolean modified = false ; for (E e : c) { add(index++, e); modified = true ; } return modified; } public void add (int index, E element) { throw new UnsupportedOperationException(); }
AbstractList 中有三个涉及到列表添加元素的方法。其中最底层都是使用声明为: add(int index, E element)
的方法。有代码实现可知,该方法的实现是抛出异常。其具体实现逻辑交由子类实现。
rangeCheckForAdd源码 1 2 3 4 private void rangeCheckForAdd (int index) { if (index < 0 || index > size()) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
该方法用于添加元素位置进行校验,插入元素的有效范围是[0, size]。
查找元素 get源码 1 abstract public E get (int index) ;
抽象方法,内部逻辑由子类实现。在AbstractList的两个常用实现类:ArrayList 和 LinkedList ,因其内部数据结构的不同,导致其内部实现逻辑完全不同。
indexOf源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public int indexOf (Object o) { ListIterator<E> it = listIterator(); if (o==null ) { while (it.hasNext()) if (it.next()==null ) return it.previousIndex(); } else { while (it.hasNext()) if (o.equals(it.next())) return it.previousIndex(); } return -1 ; }
indexOf() 方法的功能:获取参数o在集合中首次出现的索引。具体实现逻辑就是获取向后的迭代器,从列表的头部开始查找,找到后,返回所处的索引。
lastIndexOf源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int lastIndexOf (Object o) { ListIterator<E> it = listIterator(size()); if (o==null ) { while (it.hasPrevious()) if (it.previous()==null ) return it.nextIndex(); } else { while (it.hasPrevious()) if (o.equals(it.previous())) return it.nextIndex(); } return -1 ; }
lastIndexOf 方法的功能与 indexOf 方法类似,只不过lastIndexOf 方法是获取参数o在集合中最后出现的索引。
修改元素 1 2 3 public E set (int index, E element) { throw new UnsupportedOperationException(); }
与add方法一样,也是抽象方法。
删除元素 remove源码 1 2 3 public E remove (int index) { throw new UnsupportedOperationException(); }
由源码可知,该方法同add,get,set方法一样,都是抽象方法。
clear源码 1 2 3 public void clear () { removeRange(0 , size()); }
removeRange方法 1 2 3 4 5 6 7 8 9 protected void removeRange (int fromIndex, int toIndex) { ListIterator<E> it = listIterator(fromIndex); for (int i=0 , n=toIndex-fromIndex; i<n; i++) { it.next(); it.remove(); } }
该方法是移除列表中[fromIndex, toIndex) 范围内的元素。移除操作是通过迭代器的移除功能实现的。
获取迭代器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public Iterator<E> iterator () { return new Itr(); } public ListIterator<E> listIterator () { return listIterator(0 ); } public ListIterator<E> listIterator (final int index) { rangeCheckForAdd(index); return new ListItr(index); }
由 AbstractList 的源码可知,其子类会有两种遍历列表中元素的方法。一种是通过 iterator()
获取只能从头部开始向后遍历元素的迭代器Iterator对象;一种通过 listIterator()
获取既可以从头部开始遍历也可以从尾部开始遍历的ListIterator对象。
基本方法 subList源码 1 2 3 4 5 public List<E> subList (int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList<>(this , fromIndex, toIndex) : new SubList<>(this , fromIndex, toIndex)); }
从代码实现可知,获取列表的子列表其实是创建了另一个类。
equels源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public boolean equals (Object o) { if (o == this ) return true ; if (!(o instanceof List)) return false ; ListIterator<E> e1 = listIterator(); ListIterator<?> e2 = ((List<?>) o).listIterator(); while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2))) return false ; } return !(e1.hasNext() || e2.hasNext()); }
该方法是判断两个对象是否相等。前提是两个对象都是列表类型。判断的逻辑是:分别获取两个列表对象的迭代器,然后依次判断各个元素是否相等。
hashCode源码 1 2 3 4 5 6 public int hashCode () { int hashCode = 1 ; for (E e : this ) hashCode = 31 *hashCode + (e==null ? 0 : e.hashCode()); return hashCode; }
迭代器源码分析 在AbstractList的方法中,有三个获取迭代器的方法。其中iterator()
方法是获取Iterator
类型的迭代器。该迭代器只能从列表的头部开始遍历。在分析iterator()
方法的源码时,知道内部是创建了一个名为Itr
的类。
Itr 源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 private class Itr implements Iterator <E > { int cursor = 0 ; int lastRet = -1 ; int expectedModCount = modCount; public boolean hasNext () { return cursor != size(); } public E next () { checkForComodification(); try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1 ; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove () { if (lastRet < 0 ) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this .remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1 ; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification () { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
由内部源码可知,Itr 内部其实是维持了一个名为cursor
的属性。该属性是调用下一个元素的索引。即:当调用next()方法时,返回当前索引的值。名为lastRet
的属性,表示最近调用next()或previous()的返回元素索引。如果删掉此元素,该值置为-1。因此可知,在调用next获取下个元素值时,是返回索引cursor
处的元素;在调用remove删除元素时,会删除索引lastRet
处的元素。还有一处需要注意的是:在迭代器无论调用哪个方法,在调用之前都会先调用checkForComodification()
方法进行校验,校验通过后,才会有后续操作。checkForComodification方法会抛出ConcurrentModificationException
异常。这是我们在使用列表的时候可能会遇到的坑。出现这个异常是由于:在我们创建迭代器的时候,会有expectedModCount = modCount
这个赋值操作,如果在遍历的过程中,列表的数据结构被修改了,如进行了列表元素的添加或删除,会导致 modCount的值发生变化,所以会导致异常。如果想实现在使用迭代器遍历的过程中既可以修改列表的数据结构又不会产生异常,可以使用迭代器的相关方法。如add,或remove 。
ListItr 源码 AbstractList中的listIterator()
方法是获取ListIterator
类型的迭代器。该迭代器即可以从前往后遍历,也可以从后往前遍历。listIterator()
方法内部是创建了ListItr
对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 private class ListItr extends Itr implements ListIterator <E > { ListItr(int index) { cursor = index; } public boolean hasPrevious () { return cursor != 0 ; } public E previous () { checkForComodification(); try { int i = cursor - 1 ; E previous = get(i); lastRet = cursor = i; return previous; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public int nextIndex () { return cursor; } public int previousIndex () { return cursor-1 ; } public void set (E e) { if (lastRet < 0 ) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this .set(lastRet, e); expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add (E e) { checkForComodification(); try { int i = cursor; AbstractList.this .add(i, e); lastRet = -1 ; cursor = i + 1 ; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
该类继承了 Itr类,并提供了一种从列表尾部向前遍历的方法。并且添加了修改和添加元素的方法。
SubList源码 在调用AbstractList类的subList()方法时,其内部返回了SubList或者RandomAccessSubList类。
RandomAccessSubList源码 1 2 3 4 5 6 7 8 9 class RandomAccessSubList <E > extends SubList <E > implements RandomAccess { RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) { super (list, fromIndex, toIndex); } public List<E> subList (int fromIndex, int toIndex) { return new RandomAccessSubList<>(this , fromIndex, toIndex); } }
由RandomAccessSubList源码可知,RandomAccessSubList类继承了SubList类。
SubList源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 class SubList <E > extends AbstractList <E > { private final AbstractList<E> l; private final int offset; private int size; SubList(AbstractList<E> list, int fromIndex, int toIndex) { if (fromIndex < 0 ) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > list.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")" ); l = list; offset = fromIndex; size = toIndex - fromIndex; this .modCount = l.modCount; } public E set (int index, E element) { rangeCheck(index); checkForComodification(); return l.set(index+offset, element); } public E get (int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); } public int size () { checkForComodification(); return size; } public void add (int index, E element) { rangeCheckForAdd(index); checkForComodification(); l.add(index+offset, element); this .modCount = l.modCount; size++; } public E remove (int index) { rangeCheck(index); checkForComodification(); E result = l.remove(index+offset); this .modCount = l.modCount; size--; return result; } protected void removeRange (int fromIndex, int toIndex) { checkForComodification(); l.removeRange(fromIndex+offset, toIndex+offset); this .modCount = l.modCount; size -= (toIndex-fromIndex); } public boolean addAll (Collection<? extends E> c) { return addAll(size, c); } public boolean addAll (int index, Collection<? extends E> c) { rangeCheckForAdd(index); int cSize = c.size(); if (cSize==0 ) return false ; checkForComodification(); l.addAll(offset+index, c); this .modCount = l.modCount; size += cSize; return true ; } public Iterator<E> iterator () { return listIterator(); } public ListIterator<E> listIterator (final int index) { checkForComodification(); rangeCheckForAdd(index); return new ListIterator<E>() { private final ListIterator<E> i = l.listIterator(index+offset); public boolean hasNext () { return nextIndex() < size; } public E next () { if (hasNext()) return i.next(); else throw new NoSuchElementException(); } public boolean hasPrevious () { return previousIndex() >= 0 ; } public E previous () { if (hasPrevious()) return i.previous(); else throw new NoSuchElementException(); } public int nextIndex () { return i.nextIndex() - offset; } public int previousIndex () { return i.previousIndex() - offset; } public void remove () { i.remove(); SubList.this .modCount = l.modCount; size--; } public void set (E e) { i.set(e); } public void add (E e) { i.add(e); SubList.this .modCount = l.modCount; size++; } }; } public List<E> subList (int fromIndex, int toIndex) { return new SubList<>(this , fromIndex, toIndex); } private void rangeCheck (int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private void rangeCheckForAdd (int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg (int index) { return "Index: " +index+", Size: " +size; } private void checkForComodification () { if (this .modCount != l.modCount) throw new ConcurrentModificationException(); } }
由SubList源码可知,其内部维持了一个AbstractList对象和偏移量offset及SubList对象内存储的元素数。从SubList源码可以看出,当需要获得一个子List时,底层并不是真正的返回一个子List,还是原来的List,只不过在操作的时候,索引全部限定在用户所需要的子List部分而已。