1 Iterable 与 Iterator
Iterable 是个接口, 实现此接口使集合对象可以通过迭代器遍历自身元素.
public interface Iterable<T>
修饰符和返回值 | 方法名 | 描述 |
Iterator<T> | iterator () | 返回一个内部元素为 T 类型的迭代器 |
default void | forEach (ConsumerT > action) | 对内部元素进行遍历, 并对元素进行指定的操作 |
default Spliterator<T> | spliterator () | 创建并返回一个可分割迭代器 |
第一个接口 iterator()是 jdk1.5 引入的, 需要子类实现一个内部迭代器 Iterator 遍历元素
后两个接口是 JDK1.8 后新添加的, forEach(Consumer action)是为了方便遍历操作集合内的元素, spliterator()则提供了一个可以并行遍历元素的迭代器, 以适应现在 cpu 多核时代并行遍历的需求.
其中我们可以看下 default 修饰符, 这也是 Java 8 后新出现的, 我们知道, 如果我们给一个接口新添加一个方法, 那么所有他的具体子类都必须实现此方法, 为了能给接口拓展新功能, 而又不必每个子类都要实现此方法, Java 8 新加了 default 关键字, 被其修饰的方法可以不必由子类实现, 并且由 dafault 修饰的方法在接口中有方法体, 这打破了 Java 之前对接口方法的规范.
Iterator 为迭代器类, 用于遍历容器
public interface Iterator<E>
修饰符和返回值 | 方法名 | 描述 |
boolean | hasNext() | 判断迭代器所指元素是否为最后一个 |
E | next() | 下一个元素 |
default Void | remove() | 移除迭代器只想的当前元素 |
default Void | forEachRemaining(Consumer<? super E> action) | 遍历迭代器指向元素后面的所有元素 |
AbstartList 中实现了 Iterator 类作为 List 内部的迭代器, 用于访问内部元素, 其代码如下:
- private class Itr implements Iterator<E> {
- /**
- * Index of element to be returned by subsequent call to 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.
- */
- 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.
- */
- 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();
- }
- }
- View Code
- 2Collection
Collection 是容器类的接口, 里面可以存放很多 Elements, 很多容器都实现了该接口
public interface Collection<E> extends Iterable<E>
修饰符和返回值 | 方法名 | 描述 |
int | size() | 判断容器的大小 |
boolean | isEmpty() | 判空 |
boolean | contains(Object o) | 是否包含某元素 |
Object[] | toArray() | 转化为数组 |
<T> T[] | toArray(T[] a) | 将容器中所有元素拷贝到 a 中,如果 a 不够大,则拷贝到返回的数组中。(见 AbstactCollection 中实现) |
boolean | add(E e) | 添加元素 |
boolean | remove(Object o) | 移除容器中第一个出现 Object 对象,如果 Object 为 null,则移除第一个出现的 null。如果没有 Object 对象返回 false |
boolean | containsAll(Collection<?> c) | 包含 c 中所有元素 |
boolean | addAll(Collection<? extends E> c); | 将 c 中所有元素添加到容器中 |
boolean | removeAll(Collection<?> c) | 如果容器中包含 c 中的元素,删除。(调用 remove(Object)) |
default boolean | removeIf(Predicate<? super E> filter) | 移除所有符合条件的元素(JDK1.8 中引入) |
boolean | retainAll(Collection<?> c) | 保留在 c 中出现的元素,其它全部移除 |
boolean | clear() | |
boolean | equals(Object o) | 与 o 中所有元素都相等则相等 |
int | hashCode() | c1.equals(c2) 那么他们的 hashCode() 一定相等,反之不成立 |
default Spliterator<E> | spliterator() | 在所有元素之上创建一个 Spliterator |
default Stream<E> | stream() | |
default Stream<E> | parallelStream() |
上述很多函数的实现可以参考 AbstactList 中的实现
3. List
List 是一个接口, 继承了 Collection 中的所有接口, 并且添加了自身相关接口和具体实现
由上图可以看出, Collection 分成了三个分支, List 就是其中一个, 下面我们具体分析一下增加的接口
public interface List<E> extends Collection<E>
修饰符和返回值 | 方法名 | 描述 |
Collection 中的所有接口 | ||
default void | replaceAll(UnaryOperator<E> operator) | 将运算操作后的结果替换 List 中原有元素 |
default void | sort(Comparator<? super E> c) | 将 List 中所有元素排序 |
E | get(int index); | |
E | set(int index, E element) | |
E | remove(int index) | |
int | indexOf(Object o) | o 在 List 中第一次出现的位置 |
int | lastIndexOf(Object o) | o 在 List 中最后一次出现的位置 |
ListIterator<E> | listIterator() | 获取 List 的迭代器 |
ListIterator<E> | listIterator(int index) | 获取从某个位置开始的迭代器,index 为迭代器起始位置 |
List<E> | subList(int fromIndex, int toIndex) | 子 List |
上表可以看出, 增加了 和 index 相关的接口, 根据 index 对 List 进行的 getsetremove 等操作另一类添加的接口是 ListIteator 相关的, 获取 List 的迭代器
- 3.1 ListIterator
- public interface ListIterator<E> extends Iterator<E>
ListIterator 不光包含 Iterator 中的三个接口还增加了作为一个 List 迭代器应该有的接口, 如 next(),previous()等
修饰符和返回值 | 方法名 | 描述 |
Iterator 中的所有接口 | ||
boolean | hasNext() | |
E | next() | |
boolean | hasPrevious() | |
E | previous() | |
int | nextIndex() | |
int | previousIndex() | |
void | remove() | 删除 next() 返回元素 |
void | set(E e) | 替换 next() 返回的元素 |
void | add(E e) | 在 nextIndex() 后插入元素 |
首先需要明确 ListIterator 迭代器的作用:
允许我们向前向后两个方向遍历 List;
在遍历时修改 List 的元素;
遍历时获取迭代器当前游标所在位置
注意, 迭代器 没有当前所在元素一说, 它只有一个游标 ( cursor ) 的概念, 这个游标总是在元素之间, 比如这样:
迭代器的初始位置:
调用 next()后迭代器的位置
调用 previous() 游标就会回到之前位置当向后遍历完元素, 游标就会在元素 N 的后面
也就是说长度为 N 的集合会有 N+1 个游标的位置
3.2 AbstractCollection / AbstractList
在上面的继承关系图中并没有显示出 AbstractCollect 和 AbstractList 的存在, 但是在阅读源码的时候经常遇到这两个类, 下面讲一下这两个类的作用
首先需要明确的一点是 AbstractCollect 和 AbstractList 都是抽象类而不是接口, 它们分别实现了 Collection 和 List 接口中的部分函数这样继承者直接继承 AbstractXXXX 而不需要自己重复实现里面的所有接口这两个抽象类抽离了公共部分, 进行了实现, 减少后续类的工作量
ArrayList 和 LinkedList 都直接或者间接继承了 AbstartList 类下图为这两个类的继承关系:
具体这两个类里面实现了哪些接口, 请自己阅读源码不再讲解
- 3.3 ArrayList
- public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable 我们看到 ArrayList 的定义的时候很可能会出现一个疑问, 为什么它已经继承了 AbstractList 了还需要去实现 List<E > 接口? 答案是, 后面的 List<E > 可以去掉, 这里只是让阅读者明白 ArrayList 是个 List 终于好不容易到了开发者常用的类了, 有点窃喜: transient Object[] elementData; 这个很重要的成员变量 elementData 数组用来存放 ArrayList 中的元素, 当第一个元素添加进来后, 它的默认长度变为 10(java 中 transient 关键字修饰的成员变量在类序列化的过程中不会被持久化到文件中, 保证该成员变量保存信息的安全)
ArrayList 的构造函数中可以直接指定 elementData 数组的长度, 那么问题来了, 当数组已经完全被占用再向 ArrayList 中添加元素时, 如何再分配更大长度的数组? 如何把旧数据拷贝到新数组中? 答案见下面这段源码
- private void grow(int minCapacity) { // 最少需要的容量
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1); // 分配最小容量的 1.5 倍
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity); // 最大容量比较(Inter.MAX_VALUE)
- // minCapacity is usually close to size, so this is a win:
- elementData = Arrays.copyOf(elementData, newCapacity); // 将旧数据拷贝到新数组中
- }
其它接口不再细说
参考: https://www.cnblogs.com/bushi/p/6647006.html
https://www.jianshu.com/p/047e33fdefd2
来源: http://www.bubuko.com/infodetail-2517922.html