题目:分别模拟ArrayList 、LinkList 的 add() 、size() 、以及Iterator 迭代方法。并尝试模拟generic 泛型。
要求:不允许使用JDK自带的这些方法。
目的:深入了解设计模式,了解ArrayList、LinkList都共同实现了Collection接口,以及他们拥有共同的迭代方法,这种设计思想。
设计思路:
1、先创建一个Collection接口,接口中包含三个方法:add()、size()、Iterator().
2、创建Iterator类,里面分别构造hasNext()、next()方法。
注:这个类,会涉及到一个Node节点类。
3、分别创建ArrayList类、LinkList类,都实现Collection接口。
4、创建任意对象类,猫猫狗狗,都可以,用来协助测试。
5、尝试实现generic泛型,作为了解就可以。
具体实现:
一、准备工作,创建基础类。
//创建接口类,提供3个常用基础方法
public interface Collection {
void add(Object obj);
int size();
Iterator iterator();
}
//提供迭代器两个基础方法
public interface Iterator {
Object next();
Boolean hasNext();
}
//2、创建对象类,简单点儿就好
public class Cat {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat(String name) {
super();
this.name = name;
}
@Override
public String toString() {
return "Cat [name=" + name + "]";
}
}
//3、创建Node节点类(这个对于初学者,相对比较难以想象)
public class Node {
public Object objectSelf;//节点本身
public Node nextNode;//节点链接的下一个节点
public Object getObjectSelf() {
return objectSelf;
}
public void setObjectSelf(Object objectSelf) {
this.objectSelf = objectSelf;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
public Node(Object objectSelf, Node nextNode) {
super();
this.objectSelf = objectSelf;
this.nextNode = nextNode;
}
}
二、具体代码实现。
1、创建ArrayList并实现Collection接口。 知识点:对数组的自动扩充(这个不是很常用)。
注:下面的Iterator的实现,相对比较容易理解。
public class ArrayList implements Collection {
private int index=0;
private Object[] objects=new Object[10];
@Override
public void add(Object obj) {
if(index==objects.length-1) {
Object[] newObjects=new Object[objects.length*2];//如果数组的长度满了,自动扩充
System.arraycopy(objects, 0, newObjects, 0, objects.length);
objects=newObjects;
}
objects[index]=obj;
index++;
}
@Override
public int size() {
return index;
}
public Object[] getObjects() {
return objects;
}
public void setObjects(Object[] objects) {
this.objects = objects;
}
@Override
public Iterator iterator() {
return new ArrayListIterator();//下面的类可以写成内部类
}
private class ArrayListIterator implements Iterator{
private int currentIndex=0;//记录当前迭代到哪个索引了
@Override
public Boolean hasNext() {
if(currentIndex<index) return true;
return false;
}
@Override
public Object next() {
Object object=objects[currentIndex];
currentIndex ++;
return object;
}
}
}
2、创建LinkList并实现Collection接口。 难点:对LinkList本身的了解,以及设计思路。
注:LinkListIterator 具体实现,也是难点。要做重点的消化吸收。
public class LinkedList implements Collection {
Node headNode=null;//第一个节点
Node tailNode=null;//最后(尾巴)一个节点
int size=0;//已经存了几个对象
@Override
public void add(Object obj) {
Node newNode=new Node(obj,null);
// 判断这个链表是否有元素,没有的话新元素既是头也是尾
if(headNode==null) {
//当且仅当,只有一个节点时,这个节点,即是头,又是屁股。
headNode=newNode;
tailNode=newNode;
}else {
// 如果链表不为空,那么就把这个链表的最后一个节点指向这个新节点,最后把这个新节点设置为表尾
tailNode.setNextNode(newNode);
tailNode=newNode;
}
size++;
}
@Override
public int size() {
return size;
}
@Override
public Iterator iterator() {
return new LinkListIterator();
}
private class LinkListIterator implements Iterator{
Node currentNode = headNode;// 定义一个变量指向当前迭代的节点,初始值是表头
@Override
public Boolean hasNext() {
return currentNode!= null;// 判断当前节点是否为空,非空的话就说明链表还有未迭代的节点,返回true
}
@Override
public Object next() {
Object obj = currentNode.getObjectSelf();// 获得当前节点的内容
currentNode = currentNode.getNextNode();// 使指针指向下一个节点(下一个节点有可能是空值)
return obj;
}
}
}
3-1 创建ArraList的测试类,对代码进行测试。
public class ArrayTest {
//常规遍历方法
public void commWay(ArrayList list) {
Object[] objects=list.getObjects();
//特别注意:
//下面for循环()内的list.size()不能替换为objects.length(否则会报空指针异常)。
//原因:数组的长度是固定的,在这里是20。list.size()获取的是里面存有几个对象。list.size()<=objects.length
for (int i = 0; i < list.size(); i++) {
Cat cat=(Cat)objects[i];
System.out.println(cat.getName());
}
}
public static void main(String[] args) {
ArrayList list=new ArrayList();
for(int i=0;i<15;i++) {
list.add(new Cat("咪咪"+i));
}
System.out.println(list.size());
//new ArrayTest().commWay(list);
Iterator it=list.iterator();
while (it.hasNext()) {
Cat cat=(Cat)it.next();
System.out.println(cat.getName());
}
}
}
运行结果:
15
咪咪0
咪咪1
咪咪2
咪咪3
咪咪4
咪咪5
咪咪6
咪咪7
咪咪8
咪咪9
咪咪10
咪咪11
咪咪12
咪咪13
咪咪14
3-2 创建LinkList的测试类,对代码进行测试。
public class LinkTest {
public static void main(String[] args) {
Collection col=new LinkedList();
for(int i=0;i<15;i++) {
col.add(new Cat("咪咪"+i));
}
System.out.println(col.size());
Iterator it=col.iterator();
while (it.hasNext()) {
Cat cat=(Cat)it.next();
System.out.println(cat.getName());
}
}
}
测试结果:
15
咪咪0
咪咪1
咪咪2
咪咪3
咪咪4
咪咪5
咪咪6
咪咪7
咪咪8
咪咪9
咪咪10
咪咪11
咪咪12
咪咪13
咪咪14
4、模拟泛型。这个经常用,不是很难,不做累述。
//模拟泛型
public class GenericList<T> {
private int index=0;
private Object[] objects=new Object[10];
public void add(T obj) {
if(index==objects.length-1) {
Object[] newObjects=new Object[objects.length*2];
System.arraycopy(objects, 0, newObjects, 0, objects.length);
objects=newObjects;
}
objects[index]=obj;
index++;
}
public int size() {
return index;
}
public static void main(String[] args) {
GenericList<String> genericList=new GenericList<>();
genericList.add("aa");
}
}
5、总结:
所谓的这些模式,比如:iterator,在开发中经常用到,只是我们是无感的,在开发过程中,一直以为23中设计模式很神秘,一探究竟。结果是,部分模式,在无形中我们已经在用了。
无招胜有招,但是:如果时间允许,这些设计模式,还是很有必要抽时间研磨一番,不要刻意去使用或生搬硬套,用到刚刚好就好,他们的界限有时候没有那么清晰。
上面代码写的比较粗鄙,一来自己可以回味,二来,希望能起到抛砖引玉的作用。(重点在LinkList,这个开发中不常用,可以重点记忆一下)
希望能和大家共勉!