Java8实战笔记0x05

默认方法

  • 一旦类库设计者需要更新接口,向其中加入新的方法,继承该接口的代码就需要做出相应的修改。Java 8引入了新的解决方法,一是允许在接口中声明静态方法,二是引入默认方法,通过默认方法可以指定接口方法的默认实现,默认方法使用default修饰。

不断演进的API

不同类型的兼容性

  • 变更对Java程序的影响大体可以分成三种类型的兼容性:
    • 二进制级的兼容性,表示现有的二进制执行文件能无缝持续链接(包括验证、准备和解析)和运行。例如向接口添加一个方法就是二进制级的兼容,如果添加方法不被调用,那么现有程序就不会出现错误。
    • 源代码级的兼容性,表示引入变化之后,现有的程序依然能成功编译通过。例如向接口添加新的方法就不是源代码级的兼容,因为遗留代码没有实现新引入的方法,所以无法顺利通过编译。
    • 函数行为的兼容性,表示变更发生之后,程序接受同样的输入能得到同样的结果。还是例如向接口添加新的方法,是函数行为兼容的,因为新的方法没有调用,或者被实现覆盖而没有影响其表现。

默认方法的使用模式

可选方法

  • 使用默认方法,可以为那些用户不会经常使用的,但是接口中包含的方法提供一个默认实现,这样实体类就无需在自己的实现中显示地提供一个空方法。
interface Iterator<T> {
    boolean hasNext();
    T next();
    default void remove() {
        throw new UnsupportedOperationException();
    }
}

行为的多继承

  • 类型的多继承:允许实现多个接口,而接口可以有默认实现,实质上实现了多继承。
  • 用正交方法精简接口:分解实体类的不同功能点并设计接口,降低接口的重合度。
  • 注意,继承不应该成为代码复用的万金油,例如继承一个100个方法的类就不是一个好选择,因为这会引入不必要的复杂性。可以使用代理模式有效的规避这类问题。

解决冲突的规则

解决为题的三条规则

  1. 类中方法的优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
  2. 如果1.无法判断,那么子接口的优先级最高。函数签名相同时,优先选择拥有最具体实现的默认方法的接口,如果B继承了A,那么BA更具体。
  3. 如果2.也无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法

继承一个类,实现两个接口的情况

  • 注意,上图中D未覆盖hello()方法,但它实现了接口A,那么它拥有A的默认方法;此外,C实现了接口B,因此编译器会在接口A和接口Bhello()之间选择(而不是类D和接口B之间)。由于B 更加具体,所以会选择接口Bhello()方法。

冲突及如何显式地消除歧义

同时实现具有相同函数声明的两个接口

  • 上图中,编译器将无法判断哪一个接口的实现更加具体,此时应该使用显式地声明来确定使用哪一个方法,或者覆盖它。
public class C implements B, A {
    void hello() {
        B.super.hello();
    }
}

菱形继承问题

菱形问题 - 1

  • 上图中实际上只有一个方法可选,即接口A的默认方法。

菱形问题 - 2

  • 此时接口B比接口A更加具体,因此使用接口Bhello()方法。

菱形问题 - 3

  • 上面这种情况会出现冲突,需要显式指定方法。
Author: SinLapis
Link: http://sinlapis.github.io/2019/08/15/Java8实战笔记0x05/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.