一:函数式接口
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;