前言 :
为什么要引入这种Iterator这种模式?
数组直接用for循环不就好了吗~重要的理由就是可以将遍历与实现分离开来。
目的:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
这里的顺序访问即迭代器的种类,可以从后往前遍历,也可以跳跃式遍历。
不要只使用具体类来编程、要优先使用抽象类和接口来编程
迭代器模式中的角色:
- 迭代器角色(Iterator): 负责定义访问和遍历元素的接口。
- 具体迭代器角色(Concrete Iterator):实现迭代器接口,并要记录遍历中的当前位置。
- 容器角色(Container): 负责提供创建具体迭代器角色的接口。
- 具体容器角色(Concrete Container):实现创建具体迭代器角色的接口, 这个具体迭代器角色与该容器的结构相关。
迭代器接口:
最常用的就是 hasNext、next方法,前者判断是否存在下一个元素,后者用于获取该元素。
当然还有remove方法,但是在Java中,没有被使用的对象实例将会自动的被删除(GC)
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
具体的迭代器:
next方法是返回当前元素,并指向下一个元素。
hasNext返回的是boolean,表示当前集合是否存在下一个元素,大概就是确认接下来是否可以调用next方法。
public class BookShelfIterator implements Iterator{
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
if(index < bookShelf.getLength()){
return true;
}else {
return false;
}
}
@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index ++;
return book;
}
}
容器接口:
// 表示该方法只会生成一个用于遍历集合的迭代器
public interface Aggregate {
public abstract Iterator iterator();
}
具体容器实现:
该数组的大小在实例化就被指定了,Iterator方法会生成并返回这个实例。当外部想遍历书架,就会调用这个方法。
public class BookShelf implements Aggregate{
//容器中装着书
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public Book getBookAt(int index) {
return books[index];
}
public void appendBook(Book book){
this.books[last] = book;
last ++;
}
public int getLength(){
return last;
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
//加this是该实例的构造方法要传入一个BookShelf的对象
}
}
实体Book类:
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Main:
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("one book"));
bookShelf.appendBook(new Book("two book"));
bookShelf.appendBook(new Book("three book"));
bookShelf.appendBook(new Book("four book"));
Iterator it = bookShelf.iterator();
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(book.getName());
}
}
}
BookShelfIterator类发挥了Iterator的作用,构造函数会将集合实例保存在字段中,并初始index、
Iterator it = bookShelf.iterator();
多态性: 运行期的代码返回的是实现Iterator接口的、而实现Iterator接口的构造方法中又传入了该集合实例、 编译期的代码本身就是写成接口形式。
实用:
上述迭代器实现的基本原理,在大部分集合中都有实现好了迭代器的用法,而且上述的容器用的是数组、那么就会存在满了越界的情况,解决办法就是每次添加前判断是否越界、扩容方案、直接用集合。
import java.util.ArrayList;
import java.util.Iterator;
public class test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>(); // List接口实现了Iterable接口
array.add("one book");
array.add("two book");
array.add("three book");
array.add("four book");
Iterator<String> iterator = array.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
注意了,前面的Iterator是我自己实现了,这里才是导入了Java自带的util包~~
练习~
import java.util.Iterator;
public class MyString implements Iterable<Character>{
private int length;
private String str;
public MyString(String str) {
this.str = str;
this.length = str.length();
}
@Override
public Iterator<Character> iterator() {
class iter implements Iterator<Character>{
private int cur = 0;
@Override
public boolean hasNext() {
return cur < length ? true : false;
}
@Override
public Character next() {
Character c = str.charAt(cur);
cur += 2;
return c;
}
}
return new iter(); //实现Iterabler的接口,返回迭代器
}
}
// 自定义类的迭代,如跳跃取字符串字符
public class Main {
public static void main(String[] args) {
MyString str = new MyString("123456789");
for(char c : str){
System.out.print(c);
}
}
}