很久之前在我使用ArrayList进行for循环删除元素的时候,发现总会抛出数组下标越界的错误,那时候我似乎还不知道iterator进行迭代删除,好像是使用for循环处理的。在工作当中几乎很少用到集合的循环删除,现在重新学习一下迭代器iterator。
Iterator接口
迭代器接口中有三个抽象方法。
hasNext:判断容器内是否还有可供访问的元素;
next:返回迭代器刚越过的元素的引用;
remove:删除迭代器刚越过的元素。
package java.util;
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
Iterable接口
Iterable接口中定义了一个获取迭代器类的方法
package java.lang;
import java.util.Iterator;
public interface Iterable<T> {
Iterator<T> iterator();
}
Collection接口
Collection集合接口继承了Iterable接口的iterator方法,同时定义了集合抽象方法
package java.util;
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object var1);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] var1);
boolean add(E var1);
boolean remove(Object var1);
boolean containsAll(Collection<?> var1);
boolean addAll(Collection<? extends E> var1);
boolean removeAll(Collection<?> var1);
boolean retainAll(Collection<?> var1);
void clear();
boolean equals(Object var1);
int hashCode();
}
List接口
List接口继承了Collection的抽象方法(包含iterator方法),也定义了List的一些抽象方法
package java.util;
public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean contains(Object var1);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] var1);
boolean add(E var1);
boolean remove(Object var1);
boolean containsAll(Collection<?> var1);
boolean addAll(Collection<? extends E> var1);
boolean addAll(int var1, Collection<? extends E> var2);
boolean removeAll(Collection<?> var1);
boolean retainAll(Collection<?> var1);
void clear();
boolean equals(Object var1);
int hashCode();
E get(int var1);
E set(int var1, E var2);
void add(int var1, E var2);
E remove(int var1);
int indexOf(Object var1);
int lastIndexOf(Object var1);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int var1);
List<E> subList(int var1, int var2);
}
ArrayList中的iterator
ArrayList实现了List接口,所以要实现其中的iterator方法。ArrayList中定义了一个私有类Itr来实现Iterator接口,Itr类中有cursor、lastRet和expectedModCount成员变量。cursor代表下一元素索引位置,lastRet代表上一元素索引位置,cursor总是比lastRet多1,Itr依据cursor和lastRet来对ArrayList进行迭代。
public Iterator<E> iterator() {
//返回私有类实例
return new ArrayList.Itr();
}
//定义私有类Itr实现Iterator接口
private class Itr implements Iterator<E> {
//游标,指向下一元素下标,初始化默认值为0
int cursor;
//指向上一元素索引位置
int lastRet;
int expectedModCount;
//构造方法,给lastRet赋默认值为-1
private Itr() {
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
}
//是否有下一元素
public boolean hasNext() {
//如果游标不等于当前ArrayList容量大小,则还有可供访问的元素
return this.cursor != ArrayList.this.size;
}
//获取容器内下一元素
public E next() {
//快速失败检查
this.checkForComodification();
//用var1暂存cursor
int var1 = this.cursor;
//如果当前游标位置是大于或等于ArrayList的容量大小
if (var1 >= ArrayList.this.size) {
//抛错,没有这样的元素
throw new NoSuchElementException();
} else {
//用var2暂存ArrayList的Object数组
Object[] var2 = ArrayList.this.elementData;
//这里是一个快速失败机制,因为在并发环境下数组的大小可能会被改变
if (var1 >= var2.length) {
throw new ConcurrentModificationException();
} else {
//将游标+1
this.cursor = var1 + 1;
//将lastRet赋值本方法内迭代过的游标索引var1,并且返回该位置上的元素
return var2[this.lastRet = var1];
}
}
}
//移除元素方法
public void remove() {
//因为lastRet初始化值为-1,如果没有调用过next方法,这里的lastRet就还是-1
if (this.lastRet < 0) {
throw new IllegalStateException();
} else {
//快速失败检查
this.checkForComodification();
try {
//调用ArrayList的remove方法来移除迭代过(调用了next方法)的当前元素
ArrayList.this.remove(this.lastRet);
//将cursor赋值为lastRet,因为lastRet是上一次迭代的元素位置
this.cursor = this.lastRet;
//再将lastRet赋值为-1,这里赋值的主要目的是限制只能移除当前迭代过的元素
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException var2) {
throw new ConcurrentModificationException();
}
}
}
//快速检查失败机制
final void checkForComodification() {
if (ArrayList.this.modCount != this.expectedModCount) {
throw new ConcurrentModificationException();
}
}
}
ListIterator接口
ArrayList的扩展迭代器接口继承了Iterator,新增了多个抽象方法,便于迭代操作ArrayList中的元素。
package java.util;
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove();
void set(E var1);
void add(E var1);
}
ListItr私有类
ArrayList提供了listIterator方法来获取List扩展的迭代器实例,ListItr继承了ArrayList中的Itr私有类并且继承了ListIterator接口。这里的方法如果使用不当很容易报错,比如迭代器中add方法是从当前游标位置添加元素,游标后面的原来的元素都往后排,而set方法是替换某一位置上的元素,set方法里有lastRet值判断。
public ListIterator<E> listIterator() {
return new ArrayList.ListItr(0);
}
private class ListItr extends ArrayList<E>.Itr implements ListIterator<E> {
//构造方法,入参为游标值
ListItr(int var2) {
//调用父类Itr的构造方法,父类构造方法初始化
super(null);
//将游标赋值为var2,此处是0
this.cursor = var2;
}
//判断是否有前置元素,如果当前游标不为0,则这个迭代器肯定是有前置元素的
public boolean hasPrevious() {
return this.cursor != 0;
}
//获取下一个元素的索引位置,也就是当前游标的索引位置
public int nextIndex() {
return this.cursor;
}
//获取前一元素的下标索引位置,当前游标位置-1
public int previousIndex() {
return this.cursor - 1;
}
//获取迭代器前一元素
public E previous() {
//快速失败检查
this.checkForComodification();
//var1等于游标-1
int var1 = this.cursor - 1;
//如果var1小于0,抛错
if (var1 < 0) {
throw new NoSuchElementException();
} else {
//var2等于ArrayList里的对象数组elementData
Object[] var2 = ArrayList.this.elementData;
//快速失败机制
if (var1 >= var2.length) {
throw new ConcurrentModificationException();
} else {
//游标等于var1,这里就是等于上一元素的位置了
this.cursor = var1;
//然后这里再将lastRet赋值为var1,返回上一元素
return var2[this.lastRet = var1];
}
}
}
//设置元素
public void set(E var1) {
//lastRet小于0代表还没有开始循环迭代
if (this.lastRet < 0) {
throw new IllegalStateException();
} else {
//快速失败机制
this.checkForComodification();
try {
//在lastRet位置上设置元素
ArrayList.this.set(this.lastRet, var1);
} catch (IndexOutOfBoundsException var3) {
throw new ConcurrentModificationException();
}
}
}
public void add(E var1) {
//快速失败机制
this.checkForComodification();
try {
//var2赋值为当前cursor
int var2 = this.cursor;
//在当前cursor位置上设置var1
ArrayList.this.add(var2, var1);
//游标+1
this.cursor = var2 + 1;
//这里在添加完元素后将lastRet赋值为-1
this.lastRet = -1;
this.expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException var3) {
throw new ConcurrentModificationException();
}
}
}