我是靠谱客的博主 香蕉棒球,最近开发中收集的这篇文章主要介绍Iterator与Iterable接口,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Java为了方便编程,预定义了一些特定功能的接口,本文旨在保存和说明这些接口的功能和作用,也会尽量配合源码进行说明,这个会分成多篇文章进行说明,希望大家能够从中获得自己想要的知识。
本文中涉及到的接口:

Iterator<E>
Iterable<E>

一、Iterator<E>接口
1、简介:Iterator接口的主要目的是让我们自定义的类具有循环的能力,这个接口并不复杂,完全可以自己实现
2、源码:

public interface Iterator<E> {
    boolean hasNext();
    E next();
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

Iterator的接口一共有4个方法,这里需要注意的是hasNext()和next()的默认修饰词都是public abstact,但是remove()和forEachRemaining(Consumer<? super E>)的修饰词是default,default是SE8新出的特性,用法和修饰词的中文翻译差不多,就是默认,这个接口方法如果加了default修饰词就意味着这个接口的这个方法已经有了默认的实现,这个时候我们就不用再去专门实现它,这个修饰词的主要目的还是使新接口适配旧代码
3、实例:

import java.util.Iterator;

class Money implements Iterator<Money>
{
    Money(Integer i)
    {
        System.out.println("挣了"+i+"块钱");
        this.Salary = i;
    }
    Money(int i)
    {
        System.out.println("再花"+i+"块钱");
    }
    private int Salary;
    public boolean hasNext()
    {
        return Salary-- > 0? true : false;
    }
    public Money next()
    {
        return new Money(1);
    }
}
public class Try
{
    public static void main(String[] args){
        Money money = new Money(new Integer(3));
        while(money.hasNext()){
            money.next();
        }
        System.out.println("没钱了");
    }
}

输出为:

挣了3块钱
再花1块钱
再花1块钱
再花1块钱
没钱了

二、Iterable<E>接口
1、简介:简单来说Iterable是基于Iterator的又一个封装,实现了Iterable接口就可以使用forEach语法。
2、源码:

public interface Iterable<T> {
    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

根据上面我们对于deafult接口的解释,我们可以看到这个Iterable的两个方法forEach(Consumer<? super T> action),spliterator()实际上都不用我们自己实现,我们只用实现一个返回Iterator<E>的方法。
3、实例:

import java.util.*;
class Money implements Iterator<Money>,Iterable<Money>
{
    public Iterator<Money> iterator(){
        System.out.println("调用了iterator()方法");
        return new Money(new Integer(3));
    }
    Money()
    {
        System.out.println("使用默认构造器");
    }
    Money(Integer i)
    {
        System.out.println("挣了"+i+"块钱");
        this.Salary = i;
    }
    Money(int i)
    {
        System.out.println("再花"+i+"块钱");
    }
    private int Salary;
    public boolean hasNext()
    {
        System.out.println("调用hasNext()方法");
        return Salary-- > 0? true : false;
    }
    public Money next()
    {
        System.out.println("调用next()方法");
        return new Money(1);
    }
}
public class Try
{
    public static void main(String[] args){
        Money moneys = new Money();
        for(Money money : moneys);
        //使用了Iterable接口之后就可以使用forEach语法了
    }
}

输出为:

使用默认构造器
调用了iterator()方法
挣了3块钱
调用hasNext()方法
调用next()方法
再花1块钱
调用hasNext()方法
调用next()方法
再花1块钱
调用hasNext()方法
调用next()方法
再花1块钱
调用hasNext()方法

可以看到Iterator方法实际上是在第一次进入forEach循环中就被调用,随后就循环调用hasNext(),next()方法进行循环。
三、进阶分析:
我们现在要从原理和源码上去理解这两个接口是怎么工作的,先看看Iterator<E>这个接口的这个方法:

default void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    while (hasNext())
        action.accept(next());
}

这是个默认的接口方法,但是其实一开始看到这个代码我是很懵的,我们先来一步一步来看,首先看看他的参数类型:Consumer<? super E>这个Consumer肯定也是SE8标准库的代码的一部分,源码如下:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Cosumer原来也是个接口,他一共有两个方法,void accept(T)需要我们自己定义,Consumer<T> addThenConsumer<? super T>()方法是默认方法。
这个接口上面有一个注释@FunctionalInterface,这个注释是为了标明这个接口是一个函数式接口函数式接口意味着这个接口下面有且只有一个抽象方法,当然可以有多个域。特别需要注意接口下可以有多个default修饰的方法,像下面这样是可以的:

@FunctionalInterface
interface fi
{
    int i = 1;
    void show();
    default void show(int i){};
}

要自定义一个函数接口并调用比较麻烦,我们首先需要在接口中定义一个且之定义一个我理解为目标方法的的这么一种方法,这个方法不管是在接口开始定义的时候,还是在运行过程中都不需要实际的定义,我定义的接口如下:

interface FI<T>
{
    boolean test(T i);
    default FI<T> show()
    {
        return (i)->test(i);
    };
}

调用接口时也比较麻烦,因为我们不能直接像下面这样调用:

FI.test(...)

因为这个时候接口中的test方法还没有被定义,所以我们需要一种另外一种方法来调用这个接口:

public static boolean test(FI<Integer> fi, Integer n)
{
    return fi.test(n);
}

先定义一个静态方法,然后从静态方法中调用这个函数式接口:

if(Try.test( n->n>3 , 4))
{
    System.out.print("good");
}

这样就完成了对函数式接口的调用,所有代码如下:

@FunctionalInterface
interface FI
{
    boolean test(int i);
    default FI show()
    {
        return (i)->test(i);
    };
}
public class Try
{
    public static boolean test(FI fi, int n)
    {
        return fi.test(n);
    }
    public static void main(String[] agrs)
    {
        if(Try.test( n->n>3 , 4))
        {
            System.out.print("good");
        }
    }
}

需要注意的是,不管在接口中间插入任何代码都无法运行,比如:

default FI<T> show()
    {
        System.out.println("work");
        return (i)->test(i);
    };

这个work是怎么样都不会被打印出来的。
但是具体Interable中的forEach方法和Iterator中的forEachRemaining()方法是如何在底层调用的,先留个白

最后

以上就是香蕉棒球为你收集整理的Iterator与Iterable接口的全部内容,希望文章能够帮你解决Iterator与Iterable接口所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部