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;

猜你喜欢

转载自www.cnblogs.com/silentdoer/p/8966868.html