-
所有的集合类(List、Set...)都实现自Collection接口,而Collection接口又继承于Iterable接口,因此可以说所有的集合类(List、Set...)都实现了Iterable接口
-
当某个类实现Iterable接口时,我们就能称这个类是一个 "可数" 的类,也就是可以使用
iterator()
获取一个迭代器Iterator,然后使用这个Iterator实例去遍历这个类,因此所有的Collection类都能够使用迭代器Iterator来遍历-
Iterable接口
public interface Iterable<T> { //当某个类实现Iterable接口的话,就能获取到迭代器iterator //然后就能使用这个iterator去遍历此类 Iterator<T> iterator(); }
-
Iterator接口
-
如果某个类实现了Iterable接口,那麽他也需要创建一个内部类去实现一个Iterator类,让调用Iterable接口中的iterator()时,能够获取到一个iterator实例
public interface Iterator<E> { //是否有下一个元素 boolean hasNext(); //取得下一个元素 E next(); //删除最后一个获取的元素,因此调用remove()前一定得先调用一次next() void remove(); }
-
至于此Iterator接口怎麽实现,就看各个集合实现类如何定义 "下一个元素",像是ArrayList的下一个元素就是element[index+1],而HashMap的下一个元素则是hash table数组中储存的下一个entry
-
另外可以想像Iterator像是一个游标一样,一开始停在最前面,然后不停的往后走(只能向后移动),且此游标每次都是停在元素和元素的中间,当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用
-
-
使用迭代器Iterator遍历ArrayList
public class Main { public static void main(String[] args) { //ArrayList实现了Collection接口,因此他也实现了Iterable接口 //所以他可以使用iterator迭代器来遍历 List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); //调用Iterable接口中的iterator()取得此ArrayList的迭代器实例 Iterator<String> its = list.iterator(); //使用Iterator接口的hasNext()、next()来遍历此ArrayList集合实现类 while (true) { if (its.hasNext()) { String s = its.next(); System.out.println(s); } else { break; } } } }
-
-
而再进一步说,当某个类能使用迭代器Iterator来遍历时,就能使用java提供的foreach语法糖来遍历此类 (foreach语法糖其实就是简化的
iterator()
)-
foreach实际上会被编译器编译成使用迭代器
iterator()
去遍历集合,因此能使用foreach的,都是得实现Iterable接口的集合类Collection们,像是List、Set -
所以Map就没有办法直接使用foreach(因为Map没有实现Iterable接口),只有他的
map.entrySet()
、map.keySet()
、map.values()
这种返回一个集合类的方法,才能使用foreach
public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); //原代码,使用语法糖的foreach for (String s : list) { System.out.println(s); } //实际上会被编译成使用iterator去遍历 for (Iterator<String> its = list.iterator(); its.hasNext(); ) { String s = its.next(); System.out.println(s); } } }
-
-
为什麽Iterator要额外使用内部类去实现,而不是ArrayList直接实现此接口 ?
-
如果看过Collection类的源码(以ArrayList为例),可以发现ArrayList类并不是由ArrayList去实现Iterator接口,而是ArrayList有一个内部类 Itr,专门去实现Iterator接口,而ArrayList的
iterator()
方法,只是去创建一个内部类ArrayList.Itr的实例而已//ArrayList不实现Iterator接口,反而是由他的内部类进行实现 public class ArrayList<E> extends AbstractList<E> { //调用list.iterator()可以取得此list的迭代器 public Iterator<E> iterator() { return new Itr(); //实际上就是去创建一个内部类的实例 } //ArrayList中的内部类Itr,专门实现Iterator接口 private class Itr implements Iterator<E> { int cursor; //记录当前迭代到哪裡 public boolean hasNext() { ... } public E next() { ... } public void remove() { ... } } }
-
要这样设计是因为一个集合类可能同时有多个迭代器去遍历他,而每个迭代器遍历到集合的哪裡,是每个迭代器自己的事情,彼此不互相干涉,因此才需要额外使用一个内部类去实现迭代器的Iterator接口
-
如此当需要用到Iterator来遍历集合时,只需要调用
list.iterator()
,就能取得一个全新的、不受别人影响的迭代器供自己使用,而迭代器彼此之间也不会互相干涉 -
至于为什麽要特别使用内部类来实现Iterator接口,而不是创建一个Iterator公共类来供所有集合一起使用,是因为迭代器需要知道集合的内部结构,他才能知道要怎麽去实现
hasNext()
、next()
、remove()
方法,而使用内部类才能无条件的取用外部类的所有信息(包含private的变量和方法),因此才需要将Iterator提取成接口,让每个集合自己使用内部类去实现Iterator接口
-
-
Java - Iterable接口、迭代器Iterator
最新推荐文章于 2023-12-12 15:59:51 发布