0%

corejava基础知识(2)-接口和lambda表达式

本文是对 java 接口和lambda表达式的总结

接口

接口概念

接口是对类的一组需求的描述,类遵从特定的描述,实现这项服务。
例如:
这是Camprable接口

public interface Comparable<T>
{
int compareTo(T other);
}

然后在类中实现这一接口:

  1. 将类声明为实现给定的接口
  2. 对接口中所有方法进行定义
class Employee implements Comparable<Employee>
{
...
public int compareTo(Employee other) {
return Double.compare(salary, other.salary);
}
...
}

接口特性

  • 接口不是类,不能用new实例化一个接口,可是能声明接口变量,然后再引用实现了该接口的类对象
Compararble x;
x = new Employee(...); //ok

解释:

可能会问这样的接口变量有啥用呢??举个定时器的例子,Timer函数 需要接收 一个操作函数 ,但是我们不能直接传函数进去,所以我们把接口变量(引用实现了该接口的类)传进去。同时我们可以发现接口里的方法不是静态方法,因为我们需要先新建对象。

当然 javase8 中可以用 lambda表达式 传函数,见下文 lambda 表达式

  • 检查某对象是否实现某接口

if(anObject instanceof Comparable) {...}

  • 接口也可以扩展

public interface Powered extends Moveable

  • 接口中不含实例域,却可以包含常量(publice static final)
  • 可以为接口提供默认实现
public interface Comparable<<T>
{
default int compareTo(T other){return 0};
}
  • 一个类可以有多个接口

  • 继承时容易出现的问题:

例如子类继承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。
三种情况:

  1. 静态方法

    • Lambda: (args) -> ClassName.staticMethod(args)
    • 方法引用:ClassName::staticMethod
  2. 现有对象的实例方法

    • Lambda: (args) -> expr.instanceMethod(args)
    • 方法引用:expr::intanceMethod
  3. 某类的实例方法

    • Lambda: (arg0, rest) -> arg0.instanceMethod(rest)
    • 方法引用:ClassName::instanceMethod //arg0 是 ClassName 类型的

变量作用域

lambda 表达式可以访问外围方法或类中的变量,但需注意:

  • 该变量必须是最终变量,不可以重新赋值;如String
  • 在 lambda 表达式中声明与一个局部变量同名的参数或局部变量是不合法的。
  • 在一个 lambda 表达式中使用 this 关键字时, 是指创建这个 lambda 表达式的方法的 this 参数。 简单说就是没变化。