Labmda
Lambda的基本语法是
(parameters) -> expression
或者
(parameters) -> {expression;}
这里讨论一种异常情况。假设你用与Runnable同样的签名声明了一个函数接口,我们称之为Task。
1 | interface Task { |
如果我们用以前的匿名类是没问题的:1
2
3
4
5doSomething(new Task() {
void execute() {
System.out.println("Danger danger!!");
}
})
但是将这种匿名类转换为Lambda表达式时,就导致了一种晦涩的方法调用,因为Runnable和Task都是合法的目标类型:
1 | doSomething(() -> System.out.println("Danger danger!!")); |
这时候编译器会报一个编译的异常,Ambigulous method call
,这时候需要对Task尝试使用显示的类型转换来解决这种模棱两可的情况:
1 | doSomething((Task)() -> System.out.println("Danger danger!!")); |
接口默认方法
概念
Java8引入了一种新的机制。Java8中的接口现在支持在声明方法的同事提供实现。通过两种方式可以完成这种操作。
- Java8允许在接口内声明静态方法。
- Java8引入了一个新功能,叫默认方法。
在新的Collection接口中的stream和List接口中的sort都是这样的。定义如下:
1 | default Stream<E> stream() { |
默认方法设计的目的是为了解决向接口添加方法。
Java8中的抽象类和抽象接口
那么既然接口也能实现方法,抽象类也能实现方法,区别如下:
- 一个类只能继承一个抽象类,但是一个类可以实现多个接口。
- 一个抽象类可以通过实例变量(字段)保存一个通用状态,而接口是不能有实例变量的。
解决冲突的规则
先看下面的场景1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public interface A {
default void hello() {
System.out.println("Hello from A");
}
}
public interface B {
default void hello() {
System.out.println("Hello from B");
}
}
public class C implements B, A {
public static void main(String[] args) {
new C().hello();
}
}
###解决问题的三条规则
如果一个类使用相同的函数前面从多个地方继承了方法,通过三条规则可以进行判断。
- 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
- 如果无法依据第一条进行判断,那么子接口的优先级更高:函数前面相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
- 最好,如果还是无法判断,继承了多个接口的类必须通过显示覆盖和调用期望的方法,显示地选择使用哪一个默认方法的实现。
Java8引入了一种新的语法X.super.m()
,其中X是你希望调用的m方法所在的父接口。