1.迭代器Iterator
迭代器是一个对象,它的工作是遍历并选择序列中的对象。客户端程序员不关心序列底层的结构。此外,迭代器通常被称为“轻量级”对象:创建它的代价小。因此,经常可以见到对迭代器有些奇怪的限制。
Java 的Iterator 就是迭代器受限制的例子,它只能用来:
1)使用方法 iterator()要求容器返回一个 Iterator。第一次调用Iterator 的next()方法时,它返回序列的第一个元素。
2)使用next()获得序列中的下一个元素。
3)使用hasNext()检查序列中是否还有元素。
4)使用remove()将上一次返回的元素从迭代器中移除。
import
java.util.ArrayList;
import
java.util.Iterator;
import
java.util.List;
class
Cat {
private
int
id
;
public
int
getId() {
return
id
;
}
public
void
setId(
int
id) {
this
.
id
= id;
}
Cat(
int
i) {
id
= i;
}
}
public
class
Cats {
public
static
void
main(String[] args) {
List<Cat> cats =
new
ArrayList<Cat>();
for
(
int
i = 0; i < 7; i++)
cats.add(
new
Cat(i));
System.
out
.println(
"before remove:"
+cats.size());
Iterator e = cats.iterator();
while
(e.hasNext()) {
//e.remove();//java.lang.IllegalStateException
System.
out
.println(
"Cat id:"
+ ((Cat) e.next()).getId());
e.remove();
}
System.
out
.println(
"after remove:"
+cats.size());
}
}
|
结果:
before remove:7
Cat id:0
Cat id:1
Cat id:2
Cat id:3
Cat id:4
Cat id:5
Cat id:6
after remove:0
这里必须注意remove()方法的使用,在调用该方法之前必须先调用next()方法。
2.迭代器ListIterator
该迭代器只能用于各种List类的访问。ListIterator可以双向移动。
import
java.util.ArrayList;
import
java.util.Arrays;
import
java.util.List;
import
java.util.ListIterator;
public
class
ListIteration {
public
static
void
main(String[] args) {
List<String> stringList =
new
ArrayList<String>(Arrays.asList(
"a"
,
"b"
,
"c"
,
"d"
,
"e"
));
ListIterator<String> it = stringList.listIterator();
while
(it.hasNext())
System.
out
.print(it.next() +
","
+ it.nextIndex() +
","
+ it.previousIndex() +
";"
);
System.
out
.println();
//
回溯
while
(it.hasPrevious())
System.
out
.print(it.previous()+
" "
);
System.
out
.println();
System.
out
.println(stringList);
it=stringList.listIterator(2);
while
(it.hasNext()){
it.next();
it.set(
"z"
);
}
System.
out
.println(stringList);
}
}
|
结果:
a,1,0;b,2,1;c,3,2;d,4,3;e,5,4;
e d c b a
[a, b, c, d, e]
[a, b, z, z, z]
①next()得到下一个元素;previous()得到前一个元素。
②
nextIndex()得到下一个元素的索引号;previousIndex()得到前一个元素的索引号。
③hasNext()判断是否还有后继元素;hasPrevious()判断是否还有前驱元素。
④listIterator()得到该集合的迭代器;listIterator(n)得到一个子迭代器,从原集合中第n+1个元素起(注意考虑第一个元素索引号为0)至集合末尾的所有元素组成一个子迭代器。
⑤set(“newElement”)将当前元素替换为newElement。这个方法的调用类似remove()方法,需要先调用next()方法。
3.Iterable接口与Foreach
Iterable接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。因此如果创建了任何实现Iterable接口的类,都可以将它用于foreach语句中。
import
java.util.Iterator;
public
class
IterableClass
implements
Iterable<String> {
protected
String[]
words
= (
"And that is how "
+
"we know the Earth to be banana-shaped."
).split(
" "
);
public
Iterator<String> iterator() {
return
new
Iterator<String>() {
private
int
index
= 0;
public
boolean
hasNext() {
return
index
<
words
.
length
;
}
public
String next() {
return
words
[
index
++];
}
public
void
remove() {}
};
}
public
static
void
main(String[] args){
for
(String s:
new
IterableClass())
System.
out
.print(s+
","
);
}
}
|
结果:
And,that,is,how,we,know,the,Earth,to,be,banana-shaped.,
这个例子中,IterableClass类实现了Iterable接口,该接口只有一个方法:
Iterator<T> iterator();
|
使用内部类实现这个Iterator接口,该接口有三个方法:
boolean
hasNext();
E next();
void
remove();
|
但是,如果尝试把数组当作一个Iterable参数传递会导致失败。这说明不存在任何从数组到Iterable的自动转换。
import
java.util.Arrays;
public
class
ArrayIsNotIterable {
static
<T>
void
test(Iterable<T> ib){
for
(T t:ib)
System.
out
.print(t+
" "
);
}
public
static
void
main(String[] args){
test(Arrays.asList(1,2,3));
String[] strs={
"A"
,
"B"
,
"C"
};
//test(strs);ERROR
test(Arrays.asList(strs));
}
}
|
4.实现特定功能的Foreach
前面已经讨论了,foreach语法是通过Iterable接口实现移动的,所以如果需要改变foreach语句的逻辑功能,其实质就是覆盖底层Iterable中Iterator接口中三个方法的逻辑实现。下面,我们实现反向的Foreach“效果”。
import
java.util.ArrayList;
import
java.util.Arrays;
import
java.util.Collection;
import
java.util.Iterator;
@SuppressWarnings
(
"serial"
)
class
ReversibleArrayList<T>
extends
ArrayList<T> {
public
ReversibleArrayList(Collection<T> c) {
super
(c);
}
public
Iterable<T> reversed() {
return
new
Iterable<T>() {
public
Iterator<T> iterator() {
return
new
Iterator<T>() {
int
current
= size() - 1;
public
boolean
hasNext() {
return
current
> -1;
}
public
T next() {
return
get(
current
--);
}
public
void
remove() {
}
};
}
};
}
}
public
class
AdapterMethodIdiom {
public
static
void
main(String[] args) {
ReversibleArrayList<String> ral =
new
ReversibleArrayList<String>(
Arrays.asList(
"To be or not to be"
.split(
" "
)));
for
(String s : ral)
System.
out
.print(s +
" "
);
System.
out
.println();
for
(String s : ral.reversed())
System.
out
.print(s +
" "
);
}
}
|
结果:
To be or not to be
be to not or be To
在这个例子中,ReversibleArrayList类又实现了一个Iterable接口,名为reversed(),将其底层Iterator接口中的三个方法的逻辑实现为反向的遍历,就达到了反向Foreach的效果。从这个示例中,我们还可以注意到:
ReversibleArrayList<String> ral =
new
ReversibleArrayList<String>
(
…
)
;
for
(String s : ral)
//
此处的
ral
其实是
Iterable
接口的引用,因为
ReversibleArrayList
类是实现
Iterable
接口的。
|