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

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

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

@FunctionalInterface
public 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++的类多重继承,就是为了避免出现这样的情况,现在,还是出现了。







  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值