本文是对 java 接口和lambda表达式的总结
接口
接口概念
接口是对类的一组需求的描述,类遵从特定的描述,实现这项服务。
例如:
这是Camprable接口
public interface Comparable<T> |
然后在类中实现这一接口:
- 将类声明为实现给定的接口
- 对接口中所有方法进行定义
class Employee implements Comparable<Employee> |
接口特性
- 接口不是类,不能用new实例化一个接口,可是能声明接口变量,然后再引用实现了该接口的类对象
Compararble x; |
解释:
可能会问这样的接口变量有啥用呢??举个定时器的例子,Timer函数 需要接收 一个操作函数 ,但是我们不能直接传函数进去,所以我们把接口变量(引用实现了该接口的类)传进去。同时我们可以发现接口里的方法不是静态方法,因为我们需要先新建对象。
当然 javase8 中可以用 lambda表达式 传函数,见下文 lambda 表达式
- 检查某对象是否实现某接口
if(anObject instanceof Comparable) {...}
- 接口也可以扩展
public interface Powered extends Moveable
- 接口中不含实例域,却可以包含常量(publice static final)
- 可以为接口提供默认实现
public interface Comparable<<T> |
-
一个类可以有多个接口
-
继承时容易出现的问题:
例如子类继承compareTo方法时,必须要有子类与超类进行比较的思想,就像第五章equals方法一样,不然会有ClassCastException错误。
- 只有一个抽象方法,并用lambda表达式替代,这种接口叫函数式接口;不含任何方法的接口叫标记接口,如 Cloneable。
解决接口冲突
同名,且参数类型相同下:
1)超类优先
2)接口冲突:只要其中一个接口提供了默认方法,就会报错;如果都不提供,就是抽象类。
ps. 类优先的机制确保了与java SE 7 的兼容,因为那时没有默认方法。
lambda表达式
为什么引入lambda表达式呢?
Arrays.sort(strings, new LengthComparator());
这段代码用定制的比较器完成字符串排序,可以看出它传入了一个对象(接口),这个对象实现了Camparable接口,对象里面有compare方法。我们主要目的就是想传递这个方法,但是Java之前只能通过构造对象,来传递该方法。于是lambda表达式正式引入!
lambda表达式语法
例子:
(String first, String second) -> {...}
把它替换到之前到代码中:
Array.sort(strings, (fisrt, second)->first.length() - second.length());
一些细节:
- 如果可以推导出参数类型,那么类型可以不写;而且如果只有这一个参数,小括号也可以不写。
- 如果某些分支返回一个值,而另一些分支不返回值,这是不合法的。
(int) -> {if(x >= 0) return 1;} //不合法
- 对于只有一个抽象方法的接口,可以提供一个lambda,就像例子;这种接口称为函数式接口。常的用函数式接口有:Predicate, Consumer, Function, Supplier 等等。
方法引用与lambda
假如想传递的 lambda 已经有了现成的方法,那么可以用方法引用来代替lambda。
三种情况:
-
静态方法
- Lambda:
(args) -> ClassName.staticMethod(args)
- 方法引用:
ClassName::staticMethod
- Lambda:
-
现有对象的实例方法
- Lambda:
(args) -> expr.instanceMethod(args)
- 方法引用:
expr::intanceMethod
- Lambda:
-
某类的实例方法
- Lambda:
(arg0, rest) -> arg0.instanceMethod(rest)
- 方法引用:
ClassName::instanceMethod //arg0 是 ClassName 类型的
- Lambda:
变量作用域
lambda 表达式可以访问外围方法或类中的变量,但需注意:
- 该变量必须是最终变量,不可以重新赋值;如String
- 在 lambda 表达式中声明与一个局部变量同名的参数或局部变量是不合法的。
- 在一个 lambda 表达式中使用 this 关键字时, 是指创建这个 lambda 表达式的方法的 this 参数。 简单说就是没变化。