Collection的部分关系图如下
Collctions与Collection的区别
1.Collection:java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
2.Collections:Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。了解更多
Collection层次图
注:conllection接口实现了Iterable接口(1.5之后)
Iterator迭代器
Iterable(java.lang. Itreable):
Iterable是Jdk1.5之后添加的新接口, 是Collection的父接口。该接口只有一个方法(iterator()),可以获取每个容器自身的迭代器Iterator。(Collection)集合容器都需要获取迭代器(Iterator)于是在5.0后又进行了抽取将获取容器迭代器的iterator()方法放入到了Iterable接口中。Collection接口继承了Iterable,所以Collection体系都具备获取自身迭代器的方法,只不过每个子类集合都进行了重写(因为数据结构不同)
Iterator(迭代器):
为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器
迭代器就是专门取出集合元素的对象。但是该对象比较特殊,不能直接创建对象(通过new),该对象是以内部类的形式存在于每个集合类的内部。该类主要用于遍历集合对象,该类描述了遍历集合的常见方法.Collection接口中定义了获取集合类迭代器的方法(iterator()),所以所有的Collection体系集合都可以获取自身的迭代器。
Iterator:该接口是集合的迭代接口类,定义了常见的迭代方法
1:boolean hasNext() :判断集合中是否有元素,如果有元素可以迭代,就返回true。
2: E next() :返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException[返回Object类型]
3: void remove():从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)[删除的next方法返回的元素]Iterable:只有一个方法(Iterator<T> iterator()) ,用于返回集合的迭代器对象
eg:
public static void main(String agrs[]) {
Collection coll = new ArrayList();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
System.out.println(coll);
Iterator it = coll.iterator(); //因为collection实现了Iterable接口,并重写了iterator()方法、
while (it.hasNext()) {
it.next(); //当迭代器的指针已经返回到末尾的时候,再次调用next()方法,会返回NoSuchElementException异常异常。
it.remove();//删除的元素为next方法返回的元素,再删除前必须调用next()方法,否则返回IllegalStateException异常。
}
System.out.println(coll);
}
基于ArrayList的Iterator源码分析
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;//下一个元素的索引超出arrayList最后索引时时,则表示已经为最后一个元素
}
@SuppressWarnings("unchecked")
public E next() {//返回cursor的元素,并且修改cursor与laastRed的值。
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];
}
public void remove() { //删除数据结构的元素,调用ArrayList的删除的方法,
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;//所以在使用Iterator的时候不能对调用coolection的方法来改变数据结构,只能调用iterator来实现元素的删除。
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() { //判断是否数据结构是否发生结构上的修改
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
在ArrayList内部首先定义了一个内部类ITr,并通过Iterator()方法来返回内部类。
public ListIterator<E> listIterator() {
return new ListItr(0);
}
在Itr内部定义了三个int类型的变量,cursor,lastRet,expectedModCount,其中Cursor表示下一个元素的索引位置,lastRed表示上一个元素的索引位置。
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
checkForComodification()主要用来判断集合的修改次数是否合法,即用来判断遍历过程中集合是否被修改过。在进行元素取出遍历的时候,是不能对原有的数据结构进行结构上的修改。modCount用于记录ArrayList集合的修改次数,初始化为0,,每当集合被修改一次(结构上面的修改,内部update不算),如add、remove等方法,modCount + 1,所以如果modCount不变,则表示集合内容没有被修改。该机制主要是用于实现ArrayList集合的快速失败机制。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
对于remove()方法的是实现,它是调用ArrayList本身的remove()方法删除lastRet位置元素,然后修改modCount即可。所以在进行Iterator的遍历的时候,不能调用remove()方法。
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
注意:
(1)Iterator只能单向移动。
(2)Iterator.remove()是唯一安全的方式来在迭代过程中修改集合;如果在迭代过程中以任何其它的方式修改了基本集合将会产生未知的行为。而且每调用一次next()方法,remove()方法只能被调用一次,如果违反这个规则将抛出一个异常(ConcurrentModificationException)。
快速失败机制
fail-fast 机制,即快速失败机制,是java集合(Collection)中的一种错误检测机制。当在迭代集合的过程中该集合在结构上发生改变的时候,就有可能会发生fail-fast,即抛出ConcurrentModificationException异常。fail-fast机制并不保证在不同步的修改下一定会抛出异常,它只是尽最大努力去抛出,所以这种机制一般仅用于检测bug。更多
基于LinkedList的ListIterator源码分析
ListIterator是一个功能更加强大的, 它继承于Iterator接口,只能用于各种List类型的访问。可以通过调用listIterator()方法产生一个指向List开始处的ListIterator, 还可以调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
方法:
// LinkedList.java
// LinkedList 类重写了 listIterator(int index) 方法
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index); // 同理 检查 index 范围;相关代码就不贴了
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned; // 上一次处理的节点
private Node<E> next; // 即将要处理的节点
private int nextIndex; // 即将要处理的节点的 index
// modCount 表示集合和迭代器修改的次数;expectedModCount 表示当前迭代器对集合修改的次数
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
/**
* 处理对象:迭代器当前的 next 节点
* 将处理目标储到 lastReturned 变量中
* 然后将当前的 next.next 节点保存起来,用于下一次迭代处理
* nextIndex 同时 +1
* 返回 lastReturned.item 元素
* 执行后:lastReturned 指向该次处理的节点;next、nextIndex 指向该次处理节点的后一个节点
*/
public E next() {
// 检查 modCount 与 expectedModCount 是否相等
// 实际检查该链表是否被其他迭代器或者集合本身修改
checkForComodification();
// 判断是否存在 next 节点
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next; // 将这次返回的 node 节点更新到迭代器中的 lastReturned 变量
next = next.next; // 将下一次需要处理 node 节点更新会 next 变量
nextIndex++; // 变量 nextIndex +1
return lastReturned.item; // 返回元素
}
public boolean hasPrevious() {
return nextIndex > 0;
}
/**
* 处理对象:迭代器当前的 next.prev 节点
* 将处理目标储到 lastReturned 变量中
* 然后将当前的 next.prev 节点保存起来,用于下一次迭代处理
* nextIndex 同时 -1
* 返回当前的 next.item 元素
* 执行后:next、lastReturned、nextIndex 指向该次处理节点的前一个节点
*/
public E previous() {
checkForComodification();
// 判断是否存在 prev 节点
if (!hasPrevious())
throw new NoSuchElementException();
// 处理当前 next 的 prev 节点
// 特殊情况:next = null 时,则它的 prev 节点为 last 节点
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--; // nextIndex -1
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
/**
* 处理对象:lastReturned
* 删除 lastReturned 指向的节点,并置为 null
* 同时保证 next 和 nextIndex 指向同一个节点
*/
public void remove() {
checkForComodification(); // 同理, 检查 modCount 与 expectedModCount 是否相等
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next; // 暂存 lastReturned 的 next 节点,用于恢复迭代状态
unlink(lastReturned); // 删除最后返回的节点 modCount++;
// 分迭代方向处理(因为删除一个节点后,需要恢复迭代状态:next 和 nextIndex 指向同一个节点)
if (next == lastReturned) // next 与 lastReturned 节点相同则表明最近一次迭代操作是 previous()
next = lastNext; // 删除了原有 next 指向的节点,因此 nextIndex 相对指向的节点变为 next.next,需要更新 next 变量的指向
else
nextIndex--; // next() 迭代方向;删除了next前面的节点,因此next的相对位置发生变化,需要 nextIndex -1
lastReturned = null;
expectedModCount++; // 同时 expectedModCount++
}
/**
* 处理对象:lastReturned
*/
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
/**
* 分位置进行添加
*/
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
/**
* 检查 modCount 与 expectedModCount 是否相等,否则抛出错误
* ListIterator 迭代器进行增删操作时,都会同时对这两个变量 +1
* 目的:
* 使用 ListIterator 迭代器期间,LinkedList 对象有且只能当前这一个迭代器可以进行修改
* 避免 LinkedList 对象本身以及其他迭代器进行修改导致链表混乱
*/
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
总的来说 ListIterator 是记录 List 位置的一个对象,它主要的成员变量是 lastReturned、next、nextIndex 以及 expectedModCount。
- next() 处理的是 next 节点,返回 next.item
- previous() 处理的是 next.prev 节点 返回 next.prev.item
- remove() 处理的是 lastReturned 节点,并置为null,但要注意的是,删除节点后的 next 与 nextIndex 需分情况处理。
- set() 处理的是 lastReturned 节点,lastReturned.item = e
- add() 添加,并将 lastReturned 置为null
对比
Iterator(迭代器)是一种设计模式,是一个对象,用于遍历集合中的所有元素。
Iterator 包含四个方法,分别是:next()、hasNext()、remove()、forEachRemaining(Consumer<? super E> action),并且该迭代器只能够单向移动。
由于 List 类型的 Collection 是一个有序集合,对于拥有双向迭代是很有意义的。ListIterator 接口则在继承 Iterator 接口的基础上定义了:add(E newElement)、set(E newElement)、hasPrevious()、previous()、nextIndex()、previousIndex() 等方法,使得 ListIterator 迭代能力增强,能够进行双向迭代、迭代过程中可以进行增删改操作