前言
在JAVA的学习和开发中,经常需要对集合或者数组进行遍历,遍历的方法有多种:for循环、foreach、迭代器。
for循环的实现简单明了,就是循环下标,判断边界,取到每个下标的数据。至于foreach和迭代器,其实foreach在反编译以后可以看到就是迭代器实现的,因此,今天来学习一下迭代器的实现原理。
Iterable 与 Iterator
Iterable:
//Iterable用来标识可以迭代
public interface Iterable<T> {
//只有一个返回迭代器的方法
Iterator<T> iterator();
}
//集合的父接口Collection继承自Iterable,所以List和Set都有返回迭代去的方法
public interface Collection<E> extends Iterable<E> {
}
Iterator:
迭代器接口
public interface Iterator<E> {
//判断边界,是否还有下一个对象,即是否还能迭代
boolean hasNext();
//返回下一个对象
E next();
//移除当前指针指向的对象
void remove();
}
迭代器的使用流程是:
1、通过hasNext判断边界,是否可以继续迭代
2、通过next() 方法返回指针指向的对象
3、remove()方法移除指针指向的对象,remove之前必须先执行过next()
迭代器在不同的集合里有不同的实现。
下面来看下各种集合的迭代器实现,主要理解原理。
ArrayList
//迭代器
private class Itr implements Iterator<E> {
//游标
int cursor = 0;
int lastRet = -1;
//记录修改次数,每次修改+1
int expectedModCount = modCount;
//是否还有下一条数据,只需判断游标是否不等于size() ,
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() {
//一次迭代 不能remove多次
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
//更新expectedModCount为最新
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
//在迭代器之外修改数据就会报错
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
//实现从后往前遍历
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();
}
}
}
LinkedList
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
//判断下一个index<size说明有下一条
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
//索引+1
nextIndex++;
//返回数据
return lastReturned.item;
}
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
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++;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
其他的都差不多,就不贴源码了,理解原理最重要。