Java源码系列(2):Iterable接口

版权声明:知识本无差别,何必在意你我? https://blog.csdn.net/qq_33774822/article/details/82757025

对于以数组形式存储的多条数据,我们通常是用下表index来遍历数组,或进行相关操作,结构如下:

对于以链表形式存储的多条数据,我们通常是用指针next来遍历数组,或进行相关操作,结构如下:

这主要是由他们的数据结构决定的,数组是一块连续的空间存储,而链表则不是连续的空间。

接下来,是不是有人要问咦,这链表挺有顺序的啊,这不整整齐齐排好了吗?nonono,我只是为了版面好看故意排好的呢,

那真实的可能是这样的:(* ̄︶ ̄)

说到这里,那我们再来重温一下数组和链表各自的优缺点:

1.在查询或修改方面:

  • 数组因为是一段连续的空间,所以通过下标index查询,比如我要查第三个元素就很快,直接数组名[下标]就行。
  • 链表因为是不是连续的空间,所以要通过指针next来查询,比如我要查第三个元素,得从开始,挨个往后面查。

2.在新增或删除方面:

  • 数组因为是一段连续的空间,所以我比如要往第三个元素后面加一个数据,就要先把第三个元素后面的那一个元素的空间挪出来,就是先把数组长度加1,然后把第三个元素后面的数据挨个往后挪一个,然后再把要加的元素放在第三个元素后面的位置。
  • 链表因为不是一段连续的空间,所以我比如要往第三个元素后面加一个数据,只要将该数据的next赋值为第四个元素的位置,再将第三个元素的next赋值为该元素的位置。

那下面我们就来想一个问题,比如我原来是采用的数组来存储的1万名员工信息,对其进行新增,删除工作,没啥问题,然后项目中这员工达到了1000万,明显这新增,删除就扛不住了,那我们就要改为链表的形式。但是问题就来了,比如我代码中有100个地方用到了循环的方式,如果这时候改,那就得改100个,这完全就是劳动力的浪费,加入100个尚能改,那1000个,10000个呢?当当当,这篇文章的主角登场啦,那就是Iterable接口。

首先,我们得知道他是啥,他是一个Java提供给我们的一个接口,这个接口里面有啥呢,当然是看源码啦。

public interface Iterable<T> {
    Iterator<T> iterator();
}
public interface Iterator<E> {
    boolean hasNext();

    E next();

    void remove();
}

Iterable里面有一个iterator方法,该方法返回一个Iterator类型的数据,那Iterator里面有三个方法,分别是hasNext(下面是否还有元素),next(下一个元素),remove(删除刚刚遍历过的元素)。

接下来,我们就来用用,毕竟这光看理论也是不行的,得先写写。

比如有一个数组,里面的元素分别是1,3,2,4,6,需要输出该数组的元素。

public class Test {
  public static void main(String[] args) {
    //构造数组
    List<Integer> list = new LinkedList<>();
    //构造链表
    //List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(3);
    list.add(2);
    list.add(4);
    list.add(6);
    //定义iterator
    Iterator iterator = list.iterator();
    //while循环
    while (iterator.hasNext()) {//判断下面是否还有元素
      Integer number = (Integer) iterator.next();//指向下一个元素
      System.out.println(number);
    }
  }
}

运行结果如下:

这是Iterable最常见的用法,看代码中的有两种数据的构建方式,而下面的输出语句是一样的,就说明使用Iterable来遍历并不基于结构,那现在刚才提出的问题就可以解决了。就算项目在推进的过程临时换结构,只要使用Iterable就可以解决。

当然我们并不能止步于此,下面我们来思考一下,刚才我们看源码的时候,是在Iterable中使用Iterator,然后Iterator接口中有三个方面,而我们在使用他的时候,也使用了hasNext和next方法,事实上,我们刚才使用的List是继承了Collection接口,而Collection接口也继承了Iterable接口,而Iterable接口继承了Iterator接口,这样我们就发现他是挨个继承的关系,那既然我们在遍历的时候主要的方法是hasNext和next方法,那是不是就可以不必多加一层继承关系,直接让Collection继承于Iterator接口?

下面公布答案,当然是不行的,因为Iterator接口中的三个方法hasNext,next,remove都是基于当前位置的,也就是如果没有当前位置,hasNext是不知道下面有没有数据的,next是不知道下面一个元素是什么,remove是不知道将要删除哪个元素的,现在当前位置是在Iterator接口的对应实现中。如果让Collection直接继承于Iterator,势必导致集合中包含当前位置的信息,如果此时是一个进程当然没问题,但是如果是多个进程,他们对同一集合进行操作,那这些方法就都没有意义。

我们假设有两个进程对同一个集合进行操作,有个进程可能慢一点,有个进程可能快一点,他们之间相差两个位置,那在查询的时候,当前位置到底是听哪个进程的?

终于到了最后,哈哈哈,我是不会让你们开心的,来道题目练练

public class Test {
  public static void main(String[] args) {
    //构造数组
    List<Integer> list = new LinkedList<>();
    list.add(1);
    list.add(3);
    list.add(2);
    //定义iterator
    Iterator iterator = list.iterator();
    //while循环
    while (iterator.hasNext()) {//判断下面是否还有元素
      Integer number = (Integer) iterator.next();//指向下一个元素
      System.out.println(number);
            if(number==3){
                iterator.remove();
            }
     }
}

猜猜结果是啥

猜你喜欢

转载自blog.csdn.net/qq_33774822/article/details/82757025