接口、Lambda表达式与内部类
接口
接口的概念
类是对数据和功能的一组描述,同样,接口也是对数据和功能的一组描述,但是,接口不能被继承,只能被实现。
也就是说一个类如果实现了一个接口,就必须实现接口中规定的所有方法。
可以把接口看成是没有实例域的抽象类。
接口的一些特点:
接口中的方法自动地属于public。因此,在接口中声明方法时,不必提供关键字public。
接口中可以定义常量
接口中不能含有实例域
在编写代码时,使用 implements
关键字表示某个类实现了某个接口。
示例: class Employee implements Comparable
不过在 Java SE 5.0 中,Comparable接口已经改进为泛型类型。
示例:
1 | class Employee implements Comparable<Employee> |
接口的特性
接口不是类,不能实例化一个接口。
但是可以声明接口的变量,如:
1 | Comparable x; |
接口变量必须引用实现了接口的类对象:
1 | x = new Employee(...); |
可以使用
instanceof
检测一个对象是否实现了某个接口1
if (anObject instanceof Comparable){ ... };
类可以建立层次化的继承关系,接口也可以。
1
2
3
4public interface Movable
{
void move(double x, double y)
}1
2
3
4public interface Powerd extends Movable
{
double milesPerGallon();
}接口中不能包含实例域或者静态方法,但却可以包含(静态)常量。
1
2
3
4
5public interface Powerd extends Movable
{
double milesPerGallon();
double SPEED_LIMIT = 95;
}与接口中的方法都自动地被设置为
public
一样,接口中的域将被自动地设为public static final
。一个类只能拥有一个超类,但是可以实现多个接口
1
class Employee implements Cloneable, Comparable
接口与抽象类
接口和抽象类的对比:
- 一个子类只能继承一个抽象类,但是可以实现多个接口。
- 抽象类可以有实例域,接口不能有实例域。
- 抽象类和接口都可以有(静态)成员变量。抽象类的静态成员变量可以有多种访问类型,但是接口中的静态成员变量默认且只能是
public static final
。 - 抽象类可以有构造方法,接口没有构造方法。
- 抽象类可以有抽象方法或者具体方法,但是接口只有抽象方法。
- 抽象类中的方法可以是
public
、protected
,接口方法只有public
。
Comparator
接口
Java ArrayList of Object Sort Example (Comparable And Comparator)
对象克隆
lambda 表达式
lambda表达式相当于简化了匿名内部类的写法。
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。但是lambda表达式没有这个限制。
lambda表达式通常搭配 函数式接口
进行使用。
lambda的代码块只有一行的时候,可以省略 return
,Java会自动把自动把这一行代码的结果当作返回值 return
。
进阶内容
java - Implied anonymous types inside lambdas - Stack Overflow
java - Invoking a method of an anonymous class - Stack Overflow
Why can’t Java 7 diamond operator be used with anonymous classes? - Stack Overflow
java - Why can’t diamond infer types on anonymous inner classes? - Stack Overflow
关于 Lambda 的一个问题
1 | Predicate<Integer> predicate = IntStream.of(10).mapToObj(int1 -> { |
上边这段代码,编译时候会报错:
1 | error: method reduce in interface Stream<T> cannot be applied to given types; |
深入分析一下,reduce 的方法签名是:
1 | Optional<T> reduce(BinaryOperator<T> accumulator); |
即入参是一个 T,返回值需要和 T 的类型一致。
但是我们在 reduce 方法中执行的是 Predicate::and
,入参是 Predicate,返回值是 Optional<T>
。
但是实际上我们传给 Predicate::and
的参数是一个实现了 Predicate
接口的匿名类,但是返回值是一个 Predicate 类型的值。
按照 reduce 方法的方法签名要求,我们传入了一个匿名类的对象,返回值也必须是一个匿名类的对象。但是 Predicate::and
的返回值是一个 Predicate 类型的对象,那么就需要把这个 Predicate 类型的对象转换成匿名类的对象才可以,但是匿名类是 Predicate 的子类,如果这么转换,相当于把父类的对象赋值给子类的对象,Java 无法直接做转换。所以报错类型不匹配。
其实这个报错相当于下边的代码:
1 | List<Integer> list = new ArrayList<>(); |
相当于在把一个父类的引用赋值给一个子类引用。