4.7 多重继承

接口允许多重继承,因此有可能碰到两个接口包含签名相同的默认方法的情况。比如例4-19中,接口CarriageJukebox都有一个默认方法rock,虽然各有各的用途。类MusicalCarriage同时实现了接口Jukebox(例4-19)和Carriage(例4-20),它到底继承了哪个接口的rock方法呢?

例4-19 Jukebox

  1. public interface Jukebox {
  2. public default String rock() {
  3. return "... all over the world!";
  4. }
  5. }

例4-20 Carriage

  1. public interface Carriage {
  2. public default String rock() {
  3. return "... from side to side";
  4. }
  5. }
  6. public class MusicalCarriage implements Carriage, Jukebox {
  7. }

此时,javac并不明确应该继承哪个接口中的方法,因此编译器会报错:class MusicalCarriage inherits unrelated defaults for rock() from types Carriage and Jukebox。当然,在类中实现rock方法就能解决这个问题,如例4-21所示。

例4-21 实现rock方法

  1. public class MusicalCarriage
  2. implements Carriage, Jukebox {
  3. @Override
  4. public String rock() {
  5. return Carriage.super.rock();
  6. }
  7. }

该例中使用了增强的super语法,用来指明使用接口Carriage中定义的默认方法。此前,使用super关键字是指向父类,现在使用类似InterfaceName.super这样的语法指的是继承自父接口的方法。

三定律

如果对默认方法的工作原理,特别是在多重继承下的行为还没有把握,如下三条简单的定律可以帮助大家。

  1. 类胜于接口。如果在继承链中有方法体或抽象的方法声明,那么就可以忽略接口中定义的方法。

  2. 子类胜于父类。如果一个接口继承了另一个接口,且两个接口都定义了一个默认方法,那么子类中定义的方法胜出。

  3. 没有规则三。如果上面两条规则不适用,子类要么需要实现该方法,要么将该方法声明为抽象方法。

其中第一条规则是为了让代码向后兼容。