Java8引入函数接口,与原有接口多重继承带来的缺陷——走进Java Lambda(三)

来源:互联网 发布:用java计算pai的值 编辑:程序博客网 时间:2024/06/05 02:50

    我们知道函数接口可以有default方法和静态方法。我们知道静态方法不属于任何一个类,这里不会有什么问题。但是接口里面有default方法,加上接口可以多继承,这样问题就来了。不信,我们走着瞧。

跳一下。还记得吗:函数接口只允许有一个抽象方法,Lambda表达式默认实现这个抽象方法。比如要对一个参数判断是否满足某条件,一般使用Predicate,默认实现test方法,而且只在程序调用test方法后,整个表达式才执行;比如要对两个参数进行某种操作,而且返回值须与参数同类型,我们可以使用BinaryOperator默认实现apply方法,只在程序调用apply方法后,整个表达式才执行。当然也有不需传参数的函数接口Supplier,顾名思义,他就像一个供应商,你生产出来的东西,放给Supplier,需要的时候再取出来。是不是说错了,应该是需要的时候才去临时生成东西并返回吧。Supplier只定义了一个get()空方法,非常简洁。我们看看源码。

@FunctionalInterfacepublic interface Supplier<T> {    /**     * Gets a result.     *     * @return a result     */    T get();}

上面有个@FunctionalInterface注释,这个是用来干嘛的呢。它是用来告诉编译器这个接口是函数接口,若不符合函数接口规范(已经说过了),那么就会报编译错误。那么我们自己在写函数接口的时候,注意加上这么一个注释,让编译器帮忙检查一下。

    一个函数接口可以有多个default的方法,若有两个函数接口,有相同的default方法时,会怎么样呢。如下面的代码:

public class SingleTest {    FromA fromA = new FromA();    FromB fromB = new FromB();    SubFromB subFromB = new SubFromB();    FromSubAAndA fromSubAAndA = new FromSubAAndA();    XFromBAndA xFromBAndA = new XFromBAndA();    XFromBAndB xFromBAndB = new XFromBAndB();        @Test    public void  test(){        fromA.message("fromA"); //接口A的消息:fromA        fromB.message("fromB"); //类FromB的消息:fromB        fromSubAAndA.message("fromSubAAndA");//接口SubA的消息:fromSubAAndA        subFromB.message("subFromB"); //类SubFromB的消息:subFromB        xFromBAndA.message("xFromBAndA"); //类FromB的消息:xFromBAndA        xFromBAndB.message("xFromBAndB"); //类FromB的消息:xFromBAndB    }}interface A{    default void message(String msg){        System.out.println("接口A的消息:"+msg);    }}interface SubA extends A{    default void message(String msg){        System.out.println("接口SubA的消息:"+msg);    }}interface B{    default void message(String msg){        System.out.println("接口B的消息:"+msg);    }}class FromA implements A{    }class FromB implements B{    @Override    public void message(String msg) {        System.out.println("类FromB的消息:"+msg);    }}class FromSubAAndA implements SubA,A{    }class SubFromB extends FromB{    @Override    public void message(String msg) {        System.out.println("类SubFromB的消息:"+msg);    }}class XFromBAndA extends FromB implements A{    }class XFromBAndB extends FromB implements B{    }

代码中的各种关系如图:


运行上面的代码,我们发现当default方法冲突时,Java8里面遵循如下规则:

1、子接口和子类优先

2、类比接口优先

3、如果在接口多重实现中遇到了冲突,必须指定调用哪个接口的default方法

啊?3是什么意思呢?是这个意思,比如我们上面有这样一个类

class FromSubAAndA implements SubA,A{    }

编译是完全可以通过的,运行也是OK的。但是要是有这样一个类呢?同时实现了接口A、B,接口A、B又有同样的default方法。

class FromBAndA implements B,A{    }

这样编译会通不过的。发生这样的事呢,大家都不想的。我们必须重写那个相同的方法,要么另起炉灶,要么指定调用哪个接口的方法。如下:

class FromBAndA implements B,A{    @Override    public void message(String msg) {        //TODO        A.super.message(msg);// 指定使用A接口的default方法    }}

不要感觉到蛋疼,亲。C++里面是不是也有这样的问题呀?其实当初JAVA没有使用C++的类多重继承,就是为了避免出现这样的情况,现在,还是出现了。







0 0
原创粉丝点击