我刚刚了解了Java Collections Framework如何在链表中实现数据结构。 据我了解,Iterators是一种遍历列表等数据结构中各项的方式。 为什么使用此界面? 为什么方法hasNext(),next()和remove()没有直接编码到数据结构实现本身?
从Java网站:链接文本
public interface Iterator<>
An
iterator over a collection. Iterator
takes the place of Enumeration in the
Java collections framework. Iterators
differ from enumerations in two ways:
-
Iterators allow the caller to remove
elements from the underlying
collection during the iteration with
well-defined semantics.
-
Method names
have been improved.
This interface is
a member of the Java Collections
Framework.
我尝试在Google上四处搜寻,但似乎找不到确切的答案。 有人可以阐明Sun为什么选择使用它们吗? 是因为设计更好吗? 增加安全性? 好的OO实践?
任何帮助将不胜感激。 谢谢。
Why is this interface used?
因为它支持允许客户端程序员迭代任何种类的集合的基本操作(请注意:不一定是Object意义上的Collection)。
Why are the methods... not directly
coded to the data structure
implementation itself?
它们是,它们只是标记为"私人",因此您无法进入它们并与它们混为一谈。进一步来说:
-
您可以实现或子类化Iterator,以使其执行标准操作所不具备的功能,而不必更改其迭代的实际对象。
-
可以遍历的对象不需要使用遍历方法(尤其是任何高度专业化的方法)来弄乱它们的接口。
-
您可以将Iterators分发给您想要的许多客户,每个客户可以在自己的时间以自己的速度穿越。
-
如果在支持Iterator的同时修改了支持它们的存储,则特别是java.util包中的Java Iterators将引发异常。此异常使您知道Iterator现在可能正在返回无效对象。
对于简单的程序,这似乎都不值得。但是,使它们有用的那种复杂性很快就会浮现出来。
您会问:"为什么方法hasNext(),next()和remove()没有直接编码到数据结构实现本身?"。
Java Collections框架选择将Iterator接口定义为集合本身的外部化接口。通常,由于每个Java集合都实现Iterable接口,因此Java程序将调用iterator创建自己的迭代器,以便可以在循环中使用它。正如其他人指出的那样,Java 5允许我们通过for-each循环直接使用迭代器。
将迭代器外部化为其集合可允许客户端控制一个迭代器如何通过集合进行迭代。我可以想到的一个用例是,当一个人拥有一个无限制的集合时,例如Internet上所有要索引的网页。
在经典的GoF书中,非常清楚地阐明了内部和外部迭代器之间的对比。
A fundamental issue is deciding which party conrols the iteration, the iterator or the client that uses the iterator. When the client controls the iteration, the iterator is called an external iterator, and when the iterator controls it, the iterator is an internal iterator. Clients that use an external iterator must advance the traversal and request the next element explicitly from the iterator. In contrast, the client hands an internal iterator an operation to perform, and the iterator applies that operation to every element ....
External iterators are more flexible than internal iterators. It's easy to compare two collections for equality with an external iterator, for example, but it's practically impossible with internal iterators ... But on the other hand, internal iterators are easier to use, because they define the iteration logic for you.
有关内部迭代器如何工作的示例,请参见Ruby的Enumerable API,该API具有内部迭代方法,例如each。在Ruby中,其想法是将代码块(即闭包)传递给内部迭代器,以便集合可以处理自己的迭代。
重要的是使集合与指针分开。迭代器指向集合中的特定位置,因此不是集合的组成部分。这样,对于一个实例,您可以在同一个集合上使用多个迭代器。
这种分离的不利之处在于,迭代器不知道对其进行迭代的集合所做的更改。因此,您无法更改集合的结构,并且不能期望迭代器在没有"投诉"的情况下继续进行工作。
使用Iterator接口允许任何实现其方法的类充当迭代器。 Java中的接口概念应以某种方式承担合同义务,即在implements接口的类中提供某些功能,并以接口要求的方式起作用。由于必须满足合同义务才能成为有效的类,因此其他看到类implements接口的类,因此可以放心地知道该类将具有某些特定功能。
在此示例中,LinkedList类不是在LinkedList类本身中实现方法(hasNext(), next(), remove()),而是将其声明为implements和Iterator接口,因此其他人知道LinkedList可以是用作迭代器。反过来,LinkedList类将从Iterator接口(例如hasNext())实现方法,因此它可以像迭代器一样起作用。
换句话说,实现接口是一种面向对象的编程概念,旨在让其他人知道某个类具有它所声称的要具备的功能。
通过具有必须由实现接口的类实现的方法来强制执行此概念。这样可以确保要使用实现Iterator接口的类的其他类确实具有迭代器应具有的方法,例如hasNext()。
另外,应该指出的是,由于Java没有多重继承,因此可以使用接口来模拟该功能。通过实现多个接口,一个人可以拥有一个类,该类是继承某些功能的子类,并且还可以通过实现一个接口来"继承"另一个功能。一个例子就是,如果我想拥有一个LinkedList类的子类,称为ReversibleLinkedList,它可以以相反的顺序进行迭代,那么我可以创建一个名为ReverseIterator的接口,并强制它提供一个previous()方法。由于LinkedList已经实现了Iterator,因此新的可逆列表将同时实现Iterator和ReverseIterator接口。
您可以从什么是接口中阅读有关接口的更多信息。来自Sun的Java教程。
可以同时使用一个插入器的多个实例。将它们作为基础数据的本地游标进行处理。
顺便说一句:优先于具体实现的接口松散耦合
寻找迭代器设计模式,然后在这里:http://en.wikipedia.org/wiki/Iterator
因为您可能要遍历不是数据结构的内容。假设我有一个联网的应用程序,可以从服务器获取结果。我可以围绕这些结果返回一个Iterator包装器,并通过任何接受Iterator对象的标准代码将其流式传输。
将其视为良好MVC设计的关键部分。数据必须以某种方式从模型(即数据结构)到达视图。使用Iterator作为过渡,可以确保永远不会暴露Model的实现。您可能将LinkedList保留在内存中,从解密算法中提取信息或包装JDBC调用。它对视图无所谓,因为视图仅在乎Iterator接口。
最终,因为Iterator捕获了适用于大量数据结构的控件抽象。如果您对类别理论感到满意,那么您可以被这篇论文震惊:迭代器模式的本质。
一篇有趣的论文,讨论了使用迭代器的优缺点:
http://www.sei.cmu.edu/pacc/CBSE5/Sridhar-cbse5-final.pdf
我认为这是很好的面向对象的做法。您可以拥有处理各种迭代器的代码,甚至为您提供创建自己的数据结构或仅实现迭代器接口的通用类的机会。您不必担心其背后的实现方式。
只是M2C,如果您不知道的话:在for-each循环就足够的情况下,可以避免直接使用迭代器接口。
迭代器只是添加了遍历项目集合的通用方法。 i.remove()是不错的功能之一,您可以在其中从要迭代的列表中删除元素。如果您只是尝试从列表中正常删除项目,则会产生怪异的效果或引发异常。
该接口就像实现它的所有事物的契约。您基本上是说..保证实现迭代器的所有对象都具有这些行为相同的方法。如果您只想在代码中处理迭代器类型,则还可以使用它来传递迭代器类型。 (您可能不关心列表的类型是什么。您只想传递一个Iterator)您可以将所有这些方法独立地放入集合中,但不能保证它们的行为相同或什至具有相同的名称,并且签名。
好吧,第一个要点似乎允许多线程(或单线程,如果您搞砸了)应用程序,无需为并发冲突而锁定集合。例如,在.NET中,如果没有锁定或继承IEnumerable和重写方法(我们会得到例外),则无法同时枚举和修改集合(或列表或任何IEnumerable)。
迭代器可用于任何种类的集合。它们使您可以针对项目集合定义算法,而与基础实现无关。这意味着您可以处理列表,集合,字符串,文件,数组等。
从现在开始的十年后,您可以将List实现更改为更好的实现,并且该算法仍将针对该无缝运行。
Java Collections Framework中使用了java.util.Iterator接口,以允许在仍循环访问集合的同时对其进行修改。如果您只想对整个集合进行干净的迭代,请使用for-each,但是Iterators的好处是您可以获得以下功能:可选的remove()操作,对于List Iterator接口,它提供了添加功能,甚至更好()和set()操作。这两个接口都允许您遍历集合并同时在结构上进行更改。尝试在使用for-each遍历集合时修改集合会引发ConcurrentModificationException,通常是因为集合被意外修改了!
看一下ArrayList类
它内部有2个私人班级(内部班级)
称为Itr和ListItr
它们分别实现Iterator和ListIterator接口
公共类ArrayList ..... {//封闭类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| private class Itr implements Iterator<E> {
public E next() {
return ArrayList.this.get(index++); //rough, not exact
}
//we have to use ArrayList.this.get() so the compiler will
//know that we are referring to the methods in the
//enclosing ArrayList class
public void remove() {
ArrayList.this.remove(prevIndex);
}
//checks for...co mod of the list
final void checkForComodification() { //ListItr gets this method as well
if (ArrayList.this.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
}
private class ListItr extends Itr implements ListIterator<E> {
//methods inherted....
public void add(E e) {
ArrayList.this.add(cursor, e);
}
public void set(E e) {
ArrayList.this.set(cursor, e);
}
} |
}
当您调用方法iterator()和listIterator()时,它们将返回
私有类Itr或ListItr的新实例,并且由于这些内部类位于封闭的ArrayList类内,因此它们可以自由地修改ArrayList而不触发ConcurrentModificationException,除非您通过set同时(一致地)更改列表。 ()ArrayList类的()add()或remove()方法。
当您使用Java处理集合时,迭代器非常有用。
使用For-Each循环(Java1.5)遍历集合,数组或列表。
迭代器是Java中可用的许多设计模式之一。设计模式可以被认为是方便的构建块,样式,代码/结构的用法。
要了解有关Iterator设计模式的更多信息,请访问有关Iterator以及许多其他设计模式的网站。这是Iterator网站上的摘录:http://www.patterndepot.com/put/8/Behavioral.html
The Iterator is one of the simplest
and most frequently used of the design
patterns. The Iterator pattern allows
you to move through a list or
collection of data using a standard
interface without having to know the
details of the internal
representations of that data. In
addition you can also define special
iterators that perform some special
processing and return only specified
elements of the data collection.