前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java源码系列(2):Iterable接口

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

作者头像
陈琛
发布2020-06-12 15:51:04
3460
发布2020-06-12 15:51:04
举报
文章被收录于专栏:陈琛的Redis文章陈琛的Redis文章

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

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

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

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

那真实的可能是这样的:

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

1.在查询或修改方面:

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

2.在新增或删除方面:

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

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

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

代码语言:javascript
复制
public interface Iterable<T> {
    Iterator<T> iterator();
}
代码语言:javascript
复制
public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove();
}

Iterable里面有一个iterator方法,该方法返回一个Iterator类型的数据,那Iterator里面有三个方法,分别是hasNext(下面是否还有元素),next(下一个元素),remove(删除刚刚遍历过的元素)。接下来,我们就来用用,毕竟这光看理论也是不行的,得先写写。

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

代码语言:javascript
复制
 1public class Test {
 2  public static void main(String[] args) {    
 3    //构造数组
 4    List<Integer> list = new LinkedList<>(); 
 5    //构造链表   
 6    //List<Integer> list = new ArrayList<>();
 7    list.add(1);
 8    list.add(3);
 9    list.add(2);
10    list.add(4);
11    list.add(6);   
12    //定义iterator
13    Iterator iterator = list.iterator();  
14   //while循环
15    while (iterator.hasNext()) {//判断下面是否还有元素
16      //指向下一个元素
17      Integer number = (Integer) iterator.next();
18      System.out.println(number);
19    }
20  }
21}

运行结果如下:

这是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,势必导致集合中包含当前位置的信息,如果此时是一个进程当然没问题,但是如果是多个进程,他们对同一集合进行操作,那这些方法就都没有意义。

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

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

代码语言:javascript
复制
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();
      }
    }
}

猜猜结果是啥

,下一篇写哦

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 学习Java的小姐姐 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档