容器类是java当中非常重要的类。可以说,基本上每个项目都要用到容器类。通过这个设计模式,主要是反映通过接口来控制提供规定的方法名。具体的实现交给不同的具体的类去实现。collection接口是如此,iterator也是如此。
本文word版本(可下载):
http://wenku.baidu.com/view/1dc00c6acaaedd3383c4d34a.html
首先模拟实现arraylist。
package com.bjsxt.dp.iterator;
import com.bjsxt.dp.iterator.*;
publicclass ArrayListimplements Collection {
//初始化就是10个对象
Object[] objects = new Object[10];
intindex = 0;
publicvoid add(Object o) {
//如果到达数组上限,就翻倍,并且把原数组里面的所有内容复制到新数组当中
if(index ==objects.length) {
Object[] newObjects =new Object[objects.length * 2];
System.arraycopy(objects, 0, newObjects, 0,objects.length);
//最关键的一步在这里,把老数组的引用指向新数组,那么从arraylist的使用者的角度来说,是看不到内部数组翻倍了。
objects = newObjects;
}
objects[index] = o;
index ++;
}
publicint size() {
//返回的是数组当前的index,而不是数组的真实大小
returnindex;
}
//向外提供的iterator
public Iterator iterator() {
returnnew ArrayListIterator();
}
//通过一个内部类来实现iterator接口。
privateclass ArrayListIteratorimplements Iterator {
privateintcurrentIndex = 0;
//目前index的值大于数组的size,就没有下一个了。
publicboolean hasNext() {
if(currentIndex >=index)returnfalse;
elsereturntrue;
}
//返回当前数组对应的index处的对象,并把游标指向下一个位置
public Object next() {
Object o = objects[currentIndex];
currentIndex ++;
return o;
}
}
}
通过一个通用的接口,collection。
package com.bjsxt.dp.iterator;
//通过接口,约束方法的名字
publicinterface Collection {
void add(Object o);
int size();
//指定了容器类必须提供iterator方法,这个方法的返回值是Iterator
Iterator iterator();
}
通过另外一个接口,iterator
package com.bjsxt.dp.iterator;
publicinterface Iterator {
//两个方法,第一是返回一个object对象,第二是看还有没有下一个节点。
Object next();
boolean hasNext();
}
对于linklist,里面放的元素是node:
package com.bjsxt.dp.iterator;
publicclass Node {
//node的构造方法,传递两个参数,第一是数据本身,第二就是指向下一个节点的next
public Node(Object data, Node next) {
super();
this.data = data;
this.next = next;
}
public Object getData() {
returndata;
}
publicvoid setData(Object data) {
this.data = data;
}
public Node getNext() {
returnnext;
}
publicvoid setNext(Node next) {
this.next = next;
}
private Objectdata;
private Nodenext;
}
linkedlist
package com.bjsxt.dp.iterator;
import com.bjsxt.dp.iterator.Collection;
publicclass LinkedListimplements Collection {
//第一个节点
Node head = null;
//最后一个节点
Node tail = null;
//大小
intsize = 0;
//添加项目的方法
publicvoid add(Object o) {
//添加的第一个节点
Node n = new Node(o,null);
//只有一个节点的情况,它既是头又是尾
if(head ==null) {
head = n;
tail = n;
}
//每次在最后添加节点,把上一个节点的next指向新添加的节点,并把新节点的next指向null
//当前tail(也就是现在list当中的最后一个元素)的next指向新节点
tail.setNext(n);
//新节点成为新的tail,并且新tail的next自动指向null。
tail = n;
//同时增大list的size,并且size只在这里变化。
size ++;
}
publicint size() {
//返回的就是当前list的size
returnsize;
}
//@Override
public Iterator iterator() {
returnnull;
}
}
假设容器当中放的是cat
package com.bjsxt.dp.iterator;
publicclass Cat {
public Cat(int id) {
super();
this.id = id;
}
privateintid;
@Override
public String toString() {
return"cat:" +id;
}
}
主类,测试用类。
package com.bjsxt.dp.iterator;
import com.bjsxt.dp.iterator.ArrayList;
import com.bjsxt.dp.iterator.LinkedList;
publicclass Test {
publicstaticvoid main(String[] args) {
//ArrayList al = newArrayList();
//LinkedList al = newLinkedList();
//需要灵活的替换容器的类型。
//体会多态的引用,和灵活的设计模式,一般都是用父类的引用。然后new不同的子类对象。
//多态,利用父类引用指向子类对象。这里叫做面向接口的编程。
Collection c = new ArrayList();
for(int i=0; i<15; i++) {
c.add(new Cat(i));
}
System.out.println(c.size());
//容器的遍历:找到一个统一的遍历方式,事实上,iterator也只是一个接口。
//接口当中的遍历方法在每个具体的容器类当中实现。
//需要c提供一个iterator,每个具体的容器类提供不同的iterator。比如arraylist就是ArrayListIterator。
//使用来自当前容器的iterator。
Iterator it = c.iterator();
//当我能找到下一个,就把它返回。
while(it.hasNext()) {
//next方法返回的是一个object对象。注意这里没有next++方法,也就说,数组游标没有指向下一个。
//是因为具体的游标实现在每个容器内部,而不是在iterator当中。
Object o = it.next();
System.out.print(o +" ");
}
}
}
思想核心:
1. 通过一个通用的接口,collection来限制所有容器都必须实现的方法,方法名必须一致。从而在使用的时候,可以是显示通过父类的对象来指向子类的引用。也就是的多态来访问容器。
2. 每个具体的容器在实现collection当中的方法,自己添加了具体的实现。每个容器实现的方法不一样,但是对容器的使用者test.java来说,看不到内部实现的细节,使用起来都是一样。体现了面向对象的封装,隐藏思想。
3. 为了提供一个统一的遍历,在collection当时提供了iterator方法。那么所有的容器都要去提供iterator.而iterator本身是一个接口,这个接口的作用就是用来遍历容器当中的对象。在容器内部,采取了内部类的方式来实现这个接口。对于容器当中每个元素的遍历,每个容器实现的方法都不一样,但是对容器的使用者test.java来说,看不到内部实现的细节,使用起来都是一样。再一次体现了面向对象的封装,隐藏思想。
4. 注意一下iterator当中的两个方法,一个是hasNext(),这个方法的返回值是boolean,也就是说看看容器当中还有没有下一个对象。更重要的是next()方法,它的返回值是一个object对象。注意这里没有next++方法,也就说,数组游标没有指向下一个。是因为具体的游标实现在每个容器内部,而不是在iterator当中。