容器与容器遍历 多态的应用 最终用泛型实现(Object—->泛型E) 泛型使用时指定类型,但不需要强转(Object需要强转) 泛型(可以随便起,但最好见名知义)

  • Element
  • Type
  • Key
  • Value

需求

  • 自己写一容器
    • 数组实现
    • 链表实现
  • 能自由添加元素
  • 大小能动态拓展
    • List.add();
  • 实现对容器的遍历
    • 通用的便利方式——对数组、对链表
    • ❓通过接口强转回去只能打印出来不能使用?

存储结构

  • 数据结构——物理结构(就两种)
    • 连续存储——>数组
    • 非连续存储——>链表
  • 数据结构——逻辑结构
    • 二叉树——>可数组实现、可链表实现
    • 队列
    • ……

迭代器

  • 只能让每个容器实现自己的遍历
  • 不能在外面做,在外面做不光不知道该容器的结构还破坏了容器的封装性
  • 定义一迭代器,通过迭代器遍历
  • 可以不用知道具体的遍历方式而拿到里面的元素
  • 每个容器提供一个Iterator,内部自己实现
  • 迭代器中要有hasNext();和next();方法
  • 不是容器类实现Iterator接口,而是在容器类实现一内部类(嵌套类可以直接使用外部类的属性)
    • 不用内部类也没关系,但是这个类与其他类没有关系,隐藏在内部可以省很多麻烦;用公共类不能阻止别人去用他,在内部类中用private修饰更安全
    • 自己实现Iterator也行但是破坏了单一职责原则,iterator() return this;
    • 只要返回这样一个Iterator对象即可,内部怎么实现和用的人没有关系(模仿jdk的实现)
    • 这样做可以解耦
    • 迭代器迭代到哪和容器类本身没有关系
    • 迭代器只是作为容器类的一个属性但是又不当作成员变量

UML类图

image.png

Collection接口实现了Iteratorable接口

实现

Collection_接口

  1. package com.mashibing.dp.Iterator.v5;
  2. public interface Collection_ {
  3. void add(Object o);
  4. int size();
  5. Iterator_ iterator();
  6. }

Iterator接口

  1. package com.mashibing.dp.Iterator.v5;
  2. public interface Iterator_ {
  3. boolean hasNext();
  4. Object next();
  5. }

数组

  1. package com.mashibing.dp.Iterator.v5;
  2. /**
  3. * 相比数组,这个容器不用考虑边界问题,可以动态扩展
  4. */
  5. class ArrayList_ implements Collection_ {
  6. Object[] objects = new Object[10];
  7. //objects中下一个空的位置在哪儿,或者说,目前容器中有多少个元素
  8. private int index = 0;
  9. public void add(Object o) {
  10. if(index == objects.length) {
  11. Object[] newObjects = new Object[objects.length*2];
  12. System.arraycopy(objects, 0, newObjects, 0, objects.length);
  13. objects = newObjects;
  14. }
  15. objects[index] = o;
  16. index ++;
  17. }
  18. public int size() {
  19. return index;
  20. }
  21. @Override
  22. public Iterator_ iterator() {
  23. return new ArrayListIterator();
  24. }
  25. private class ArrayListIterator implements Iterator_{
  26. private int currentIndex = 0;
  27. @Override
  28. public boolean hasNext() {
  29. if(currentIndex >= index) return false;
  30. return true;
  31. }
  32. @Override
  33. public Object next() {
  34. Object o = objects[currentIndex];
  35. currentIndex ++;
  36. return o;
  37. }
  38. }
  39. }

链表

  1. package com.mashibing.dp.Iterator.v5;
  2. /**
  3. * 相比数组,这个容器不用考虑边界问题,可以动态扩展
  4. */
  5. class LinkedList_ implements Collection_ {
  6. Node head = null;
  7. Node tail = null;
  8. //目前容器中有多少个元素
  9. private int size = 0;
  10. public void add(Object o) {
  11. Node n = new Node(o);
  12. n.next = null;
  13. if(head == null) {
  14. head = n;
  15. tail = n;
  16. }
  17. tail.next = n;
  18. tail = n;
  19. size++;
  20. }
  21. private class Node {
  22. private Object o;
  23. Node next;
  24. public Node(Object o) {
  25. this.o = o;
  26. }
  27. public Object getObject() {
  28. return o;
  29. }
  30. }
  31. public int size() {
  32. return size;
  33. }
  34. @Override
  35. public Iterator_ iterator() {
  36. return new LinkedListIterator();
  37. }
  38. private class LinkedListIterator implements Iterator_{
  39. private Node currentIndex = head;
  40. @Override
  41. public boolean hasNext() {
  42. if(currentIndex == tail) return false;
  43. return true;
  44. }
  45. @Override
  46. public Object next() {
  47. currentIndex = currentIndex.next;
  48. return currentIndex.getObject();
  49. }
  50. }
  51. }

使用

  1. package com.mashibing.dp.Iterator.v5;
  2. import java.util.Iterator;
  3. /**
  4. * v1:构建一个容器,可以添加对象
  5. * v2:用链表来实现一个容器
  6. * v3:添加容器的共同接口,实现容器的替换
  7. * v4:如何对容器遍历呢?
  8. * v4:用一种统一的遍历方式,要求每一个容器都要提供Iterator的实现类
  9. * 作业:实现LinkedList的Iterator
  10. */
  11. public class Main {
  12. public static void main(String[] args) {
  13. Collection_ list = new ArrayList_();
  14. for(int i=0; i<15; i++) {
  15. list.add(new String("s" + i));
  16. }
  17. System.out.println(list.size());
  18. //这个接口的调用方式:
  19. Iterator_ it = list.iterator();
  20. while(it.hasNext()) {
  21. Object o = it.next();
  22. System.out.println(o);
  23. }
  24. }
  25. }

jdk中的Iterator(源码见jdk)

  1. package com.mashibing.dp.Iterator.v6;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.Iterator;
  5. /**
  6. * v1:构建一个容器,可以添加对象
  7. * v2:用链表来实现一个容器
  8. * v3:添加容器的共同接口,实现容器的替换
  9. * v4:如何对容器遍历呢?
  10. * v4:用一种统一的遍历方式,要求每一个容器都要提供Iterator的实现类
  11. * 作业:实现LinkedList的Iterator
  12. * v6:JDK的容器的Iterator
  13. */
  14. public class Main {
  15. public static void main(String[] args) {
  16. Collection c = new ArrayList();
  17. for(int i=0; i<15; i++) {
  18. c.add(new String("s" + i));
  19. }
  20. Iterator it = c.iterator();
  21. while(it.hasNext()) {
  22. System.out.println(it.next());
  23. }
  24. }
  25. }

泛型实现

实现详见gitlab

🤏随想

  1. 用父类引用子类调用子类重写的父类方法时调用的是子类重写的方法(String的toString和Object的toString)
  2. 用父类引用子类调用子类自己的方法时必须要进行强制类型转换