zoukankan      html  css  js  c++  java
  • Java8函数式接口/Lambda表达式/接口默认方法/接口静态方法/接口冲突方法重写/lambda表达式指定泛型类型等

    一:函数式接口

    1.函数式接口的概念就是此接口必须有且只能有一个抽象方法,可以通过@FunctionalInterface来显示规定(类似@Override),但是没有此注解的但是只有一个抽象方法的接口也是函数式接口;(接口也和类一样有包访问权限,但是内部的方法则默认是public)

    @FunctionalInterface
    public interface IFoo{
        void print();
    }  // 就是一个最简单的函数式接口,但是如果再有个如void print2()抽象方法则这个接口不是函数式接口会在编译时便报错(因为有@FunctionalInterface)

    2.接口里可以有静态方法(JDK8的新特性)

    @FunctionalInterface
    public interface IFoo{
        void print();
        static void sTest(){
          System.out.println("msg");
        }      
    }

    注意,接口里的静态方法默认且只能是public的,就像接口里的字段默认且只能是public static的;调用时可以直接IFoo.sTest();

    3.接口里也可以有default方法(JDK8新特性)

    @FunctionalInterface
    public interface IFoo{
        void print();
        default void sTest(){
          System.out.println("msg");
        }      
    }

    与静态方法不同的是default方法本质上是实例方法,因此仍然需要创建IFoo的实现类对象才能调用此方法,如(new IFoo(){...}).sTest();是可以的但是IFoo.sTest()则错误

    4.当一个接口成为了函数式接口后且也是以函数式接口来使用,它就类似C#里的委托,即接口和其里面的抽象方法是一一对应的,故泛型的声明要在接口名里而非抽象方法里

    @FunctionalInterface
    public interface IFoo<T extends Serializable>{
        T print(T arg);  // 写成<T> T print(T);对于将IFoo看成委托而言是错误的写法;注意<T extends B> T print。。在普通接口里也是可以的;
        static void sTest(){
          System.out.println("msg");
        }      
    }

    5.函数式接口对象和其Lambda表达式的关系

    lambda表达式不会产生里面类的.class文件,而如new Predicate(){...}是会产生的,因此如果需要将lambda表达式转换为接口对象是需要强制转换的,如:((Predicate) o -> false).and(o -> false)

    上面的(o -> false)是一个”函数对象“,它和new Predicate(){@Override test...}是不一样的,前者并没有产生Predicate的实现类,因此需要做一个强制类型转换将lambda表达式产生的结果转换为接口实现类对象;

    6.将函数式接口当成委托使用

    public interface Println<T>{
        void println(T msg);
    }

    可以Println<String> println = System.out::println;来赋值;

    7.实现多个接口但是又同名的default方法时必须重写/重定义该方法(如果是抽象方法则无所谓,当子类实现IC时实现print那么实际上即是实现IA的也是IB的不存在要重写两次的说法)

    public interface IA{
        default void print(){}
    }
    public interface IB{
        default void print(){}
    }
    public interface IC extends IA, IB{
        @Override
        default void print(){IA.super.print();}  // TODO 用于明确指定用IA的print,注意在JDK8以前由于没有default且只能继承一个类,因此只需要super.print()即可
    }

    8.lambda表达式的类型推导

    如果是非泛型自然不需要,但是如果参数是泛型,但又无法隐式推导出时可以通过(String s) ->{..}来指定泛型的类型;

    9.接口里可以都是default方法,此时这个接口可以直接new ITest{}就可以产生对象,但也可以重写default方法

    10.可以在子接口里重写父接口的default方法令其在子接口里成为抽象方法;

    11.lambda表达式和匿名内部类的区别

    lambda表达式是很特殊的存在,它不会生成.class文件,而且它也不是接口的实现类的对象,应该这么理解IFoo foo = ()->true;是IFoo能够匹配右边的lambda表达式,而不是说这个正则表达式是一个IFoo的匿名实现类的对象;

    注意上面存在一个隐式的转换即IFoo foo = (IFoo) ()->true;

    12.将方法存储到“委托”里

    ITest del = System::getenv;  // 此时通过System.getenv方法实现了ITest的抽象方法;

    del.method("string");注意,这里有几个重点,1)是ITest必须是函数式接口;2)ITest中的抽象方法名字任意且可以有泛型,但是必须能匹配System.getenv(..)这个方法的返回值和参数列表;3)del和C#的委托变量还是有些不一样的不能直接del(..)来调用,而是要del.method(..)来调用System.getenv方法;

    n)还可以用ITest t = String::new;表示String的构造方法;那么t.func(..)方法的就是new String(..)而产生的对象;(构造方法某种程度上可以理解为类的静态方法)

    n)IFoo2<String> ss = sbs::concat;,sbs是一个对象,因此ss.func(..)实际是是调用sbs.concat(..)方法

    n)对于如果方法test是类A的实例方法,则ITest del = A::test;是错误的,IDE提示没有static的test方法,因为当del.func(..)调用时将不知道要调用哪个对象的test方法,因为test的调用必须依赖某个A对象;

    补充:

    1.lambda表达式里是可以将隐藏的this参数也作为参数的,比如接口里有唯一的抽象方法String test(String str);,那么lambda表达式里可以用Object::toString作为它的参数的(toString是实例方法obj.toString(),它显示里没有参数但是实际上有个this参数);

    2.当存在方法:public <T> T execute(RedisCallback<T> action)时,用lambda表达式作为它的参数必须用(RedisCallback<Boolean>) connection -> {..}这种形式转换,这个特点是RedisCallback的T和execute的T进行了关联;

    这里之所以必须强制转换,是因为java只允许从调用处开始往下一级一级的推算泛型,比如调用处是 a,然后它可以推算出a调用的b的泛型,然后再推算出b调用的c的泛型,而不能从a里先推算出c的泛型然后再网上递推出b处的泛型;

  • 相关阅读:
    【贪心】【堆】Gym
    【并查集】Gym
    【拓扑排序】【bitset】Gym
    【递归】【线段树】【堆】AtCoder Regular Contest 080 E
    【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel
    【动态规划】【滚动数组】【bitset】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem J. Terminal
    【二分】【字符串哈希】【二分图最大匹配】【最大流】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem I. Minimum Prefix
    【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game
    【推导】【构造】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem E. Space Tourists
    【推导】【贪心】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem D. Clones and Treasures
  • 原文地址:https://www.cnblogs.com/silentdoer/p/8966868.html
Copyright © 2011-2022 走看看