一、结构图
二、Iterable接口
1、结构
实现此接口的对象可以成为for-each语句的循环目标。所有集合都要实现这个接口,因为集合总归是需要遍历的,你不能只存数据而不去获取,只要获取数据就需要用到迭代器。
2、方法介绍
Iterator<T> iterator();
返回一个迭代器对象,那么什么是迭代器呢?
public interface Iterator<E> {
// 是否有下一个元素
boolean hasNext();
// 下一个元素
E next();
// 删除迭代过的元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 对于剩下的元素执行accept方法
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
官方文档介绍说它取代了集合的枚举类 Enumeration
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
}
Enumeration类和Iteration类有两点不同,Iteration多了一个remove方法,而且对方法名进行了改进。
方法介绍:
boolean hasMoreElements():测试此枚举类是否包含更多元素。
E nextElement():返回枚举类的下一个元素,如果没有返回null。
boolean hasNext():返回迭代器是否有下一个元素。
E next():返回迭代器的下一个元素。
default void remove():接口默认实现是抛异常,删除迭代器返回的最后一个元素,注意这个方法只能在调用next方法后调用一次且仅此一次。
default void forEachRemaining(Consumer<? super E> action):默认实现是对于迭代器的每个剩余元素执行action消费型函数式接口,这个我会在JDK8新特性Stream流中详细讲解。
我们再回到Iterable接口,Iterator iterator()是返回一个T类型的迭代器。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
对于每个迭代器中的元素执行消费型函数式接口。
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
返回Spliterator接口,分割式遍历。Stream流介绍。
三、Conllection接口
1、结构
2、方法介绍
int size();
返回集合中元素个数,如果大于Integer.MAX_VALUE返回Integer.MAX_VALUE。
boolean isEmpty();
判断集合是否为空。
boolean contains(Object o);
判断集合中是否包含元素o这里调用的是o.equals(element)方法,如果o是null,那么仅当存在element=null时返回true。
Iterator<E> iterator();
返回集合中的迭代器,不保证迭代的顺序。
Object[] toArray();
将集合转换为数组,转换的数组和集合在内存中没有任何交集,是否保证迭代顺序由子类决定。
<T> T[] toArray(T[] a);
返回一个包含此集合中所有元素的数组;返回数组的运行时类型是指定数组的类型。如果集合适合指定的数组,则在其中返回。否则,将使用指定数组的运行时类型和此集合的大小分配一个新数组。返回一个包含此集合中所有元素的指定运行时类型的数组,如果数组长度比集合大小大,数组剩余空间设置成null,顺序要与迭代器的顺序一致。
boolean add(E e);
确保此集合包含指定的元素。如果此集合因调用而更改,则返回 true。 (如果此集合不允许重复且已包含指定元素,则返回 false。)支持此操作的集合可能会限制可以添加到此集合中的元素。特别是,一些集合会拒绝添加空元素,而另一些集合会对可能添加的元素类型施加限制。集合类应该在他们的文档中清楚地指定对可以添加哪些元素的任何限制。如果集合由于任何原因而拒绝添加特定元素,而不是因为它已经包含该元素,则它必须抛出异常(而不是返回 false)。这保留了在此调用返回后集合始终包含指定元素的不变性。
boolean remove(Object o);
删除集合中的单个实例。
boolean containsAll(Collection<?> c);
如果c集合的所有元素在当前集合中都能找到,则返回ture。
boolean addAll(Collection<? extends E> c);
将c集合中的元素加入到当前集合中,如果改变了当前集合就返回true。
boolean removeAll(Collection<?> c);
删除包含在指定集合中的所有此集合的元素(可选操作)。此调用返回后,此集合将不包含与指定集合相同的元素。如果改变了当前集合就返回true。
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
删除此集合中满足给定谓词的所有元素。在迭代期间或由谓词引发的错误或运行时异常被中继到调用者。如果改变了当前集合就返回true。
boolean retainAll(Collection<?> c);
仅保留此集合中包含在指定集合中的元素(可选操作)。换句话说,从该集合中移除所有未包含在指定集合中的元素。如果改变了当前集合就返回true。
void clear();
删除集合中的全部元素。
boolean equals(Object o);
重写equals方法要小心,List和Set接口规定了具体的实现。
int hashCode();
重写hashCode方法也要重写equals方法。
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
这仨在Stream流中介绍。
四、AbstractCollection抽象类
给出了Collection接口的默认实现
1、方法介绍
public boolean isEmpty() {
return size() == 0;
}
用集合大小是否为0来判断是否为空。
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
首先判断o是否为空,根据是不是空来调用==null或equals方法。
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
是不是感觉看不懂啊,为什么会操作地这么麻烦,直接用迭代器遍历一遍不就好了吗???其实不是这样的,官方文档介绍说如果你在执行这个方法的时候集合是允许修改的,如果集合的元素个数发生改变就会出错,它使用每次循环时判断hasNext和循环结束时将剩余集合中内容拷贝来分别解决元素减少和元素增加的情况。
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { // fewer elements than expected
if (a == r) {
r[i] = null; // null-terminate
} else if (a.length < i) {
return Arrays.copyOf(r, i);
} else {
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
// more elements than expected
return it.hasNext() ? finishToArray(r, it) : r;
}
public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}
private static native Object newArray(Class<?> componentType, int length)
throws NegativeArraySizeException;
这里它也是支持并行修改的,首先设置返回数组长度,如果a.length > size就返回数组a,否则新创建一个长度为size的空数组。
之后进行迭代,将迭代的值赋给r数组,如果迭代数小于r数组的长度则进入判断,若a == r说明没有创建新数组,我们将下标为i的元素置为null代表到这里就结束了;若a.length < i我们就需要将r中前i个元素赋值给新一个数组并返回;否则就说明虽然创建了新数组,但是在遍历的时候集合元素减少,导致不需要创建新数组了,这时候我们将r中的i个元素拷贝到a中,把下标为i置为null并返回a。
若集合在执行该方法的时候并行添加元素就会返回finishToArray(r, it),下面我们来看看这个方法干什么了。
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
这个方法将容量大小扩容为原来的1.5倍+1,如果超过最大数组容量(最大容量不一定是Integer.MAX,因为不同的虚拟机厂商会添加头文件)就会取最大整数或最大数组容量。最后返回扩容复制后的数组。
public boolean add(E e) {
throw new UnsupportedOperationException();
}
添加方法让子类去实现。
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
迭代器遍历,对null和非null分别处理。
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
对c中的每个元素当作参数传入contains方法,之前有介绍。
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
设置标志位记录集合是否改变。
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
对于当前集合中的所有元素进行判断,判断是否存在于c集合中,若存在则删除。
public void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
清空集合。
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
字符串拼接。
五、List接口介绍
1、结构
有序集合(也称为序列)。 实现此接口的实现类可以精确地控制每个元素在列表中的插入位置。 用户可以通过它们的整数索引(在列表中的位置)访问元素,并在列表中搜索元素。
2、方法介绍
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
// Appends the specified element to the end of this list (optional operation).
boolean add(E e);
// Removes the first occurrence of the specified element from this list, if it is present
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
以上方法都是继承自接口Collection中的内容,只不过是按照指定顺序进行规定。
boolean addAll(int index, Collection<? extends E> c);
在指定位置插入集合c,集合中index之后元素向后移动,线程不安全, 当多个线程操作时没有定义处理方法。
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
// a list iterator over the elements in this list (in proper sequence)
ListIterator<E> listIterator();
/*
列表的迭代器,允许程序员沿任意方向遍历列表,在迭代期间修改列表,并获取迭代器在列表中的当前位置。
ListIterator没有当前元素; 它的光标位置总是位于调用previous()返回的元素和调用next()返回的元素之间。
长度为n的列表的迭代器有n+1可能的光标位置,如下面的插入符号 ( ^ ) 所示:
Element(0) Element(1) Element(2) ... Element(n-1)
cursor positions: ^ ^ ^ ^ ^
请注意, remove和set(Object)方法不是根据光标位置定义的;
它们被定义为对调用next或previous()返回的最后一个元素进行操作。
*/
public interface ListIterator<E> extends Iterator<E> {
// 如果此列表迭代器在向前遍历列表时有更多元素,则返回true 。
boolean hasNext();
// 返回列表中的下一个元素并移动光标位置。
E next();
// 如果此列表迭代器在反向遍历列表时有更多元素,则返回true。
boolean hasPrevious();
// 返回列表中的前一个元素并向左移动光标位置。
E previous();
// 返回后续调用next将返回的元素的索引。
int nextIndex();
// 返回后续调用previous将返回的元素的索引
int previousIndex();
// 从列表中删除由 next 或 previous (可选操作)返回的最后一个元素。
// 每次调用下一个或上一个时只能进行一次此调用。
// 只有在最后一次调用 next 或 previous 之后还没有调用 add 时才可以进行。
void remove();
// 将next或previous返回的最后一个元素替换为指定的元素(可选操作)。
// 仅当在最后一次调用next或previous之后没有调用remove和add才能进行此调用。
void set(E e);
// 元素被插入到 next 将返回的元素之前(如果有),以及 previous 将返回的元素之后(如果有)。
// 新元素插入到隐式游标之前:对 next 的后续调用不受影响,对 previous 的后续调用将返回新元素。
void add(E e);
}
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
*
* @param <T> the type of the input and output of the operator
* @return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
这个方法使用listIterator迭代器遍历,将所有元素执行函数式接口并保存。
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);
}
}
将集合转换为数组,使用Arrays.sort方法传入一个Comparator接口,根据Comparator中的规则进行排序,之后用listIterator列表迭代器重置列表的值。
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
增删改查在列表中下标为index位置的元素。
ListIterator<E> listIterator(int index);
返回迭代器调用next方法返回index下标元素处的列表迭代器。
List<E> subList(int fromIndex, int toIndex);
返回下标从fromIndex开始,toIndex - 1结束的子列表,其中对子列表的修改会影响到当前列表(比如调用sort、clear方法)。
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
先不介绍。
六、AbstractList抽象类
这个抽象类提供了List接口的大多数实现,之后的ArrayList和LinkedList只需要继承这个抽象类并重写抽象方法即可。
1、结构如下
2、方法介绍
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
这里默认了什么都可以添加,包括多个null对象。
abstract public E get(int index);
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
这些方法都没有实现,让子类去实现,这是因为父类不知道子类存储数据的数据结构是什么,比如链表的get(int index)方法就需要一个一个遍历,但是数组的get(int index)却可以通过下标进行随机访问。
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;
}
使用列表迭代器来操作。
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;
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
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();
}
}
}
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
* 后续调用 next 将返回的元素索引。
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
* 最近调用 next 或 previous 返回的元素索引。
* 如果通过调用 remove 删除此元素,则重置为 -1。
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
* 迭代器认为支持列表应该具有的 modCount 值。
* 如果违反此期望,则迭代器已检测到并发修改。
*/
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();
}
}
这个方法创建了一个指向末尾的迭代器,那么他是怎么实现的呢?listIterator方法首先判断是否越界,如果没有则返回一个列表迭代器实现类ListItr。
ListItr频繁调用了checkForComodification方法,这是干什么的呢?checkForComodification方法判读了modCount 和 expectedModCount是否相等,如果不相等就抛出异常,modCount字段代表此列表在结构上被修改的次数。 结构修改是指那些改变列表大小的修改,或者以其他方式扰乱它,以致正在进行的迭代可能会产生不正确的结果。
public void clear() {
removeRange(0, size());
}
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();
}
}
清空列表。
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;
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size())
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
首先进行范围判断,之后调用add方法。
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);
}
返回迭代器。
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
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();
}
}
// RandomAccess接口:List实现使用的标记接口来指示它们支持快速(通常是恒定时间)随机访问。
// 此接口的主要目的是允许通用算法改变其行为,以在应用于随机或顺序访问列表时提供良好的性能。
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);
}
}
这里你可以理解为它根本没有为子列表开辟空间,而仅仅只维护一个当前列表,对子列表的操作都直接调用当前列表的方法,如子列表上调用add(index, e)方法就是在当前列表调用add(index + offset, e)。
完结撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。