在这个Java例子中,对于"super"关键字感到困惑

6
在Java官方网站的教程页面中,通过一个例子来说明两个接口定义了相同的默认方法startEngine()。类FlyingCar实现了这两个接口,并且因为明显的冲突必须覆盖startEngine()方法。
public interface OperateCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}
public interface FlyCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}

public class FlyingCar implements OperateCar, FlyCar {
    // ...
    public int startEngine(EncryptedKey key) {
        FlyCar.super.startEngine(key);
        OperateCar.super.startEngine(key);
    }
}

我不明白为什么在 FlyingCar 中,super 被用来引用 OperateCarFlyCar 接口中的 startEngine(),因为据我所知,startEngine() 没有在任何父类中被定义,因此不应该被视为驻留在其中的一个。我也看不出 superFlyingCar 中实现的这两个接口之间有任何关系。


4
super 单独使用时表示超类。FlyCar.super 是 Java 8 中的新特性,表示在接口 FlyCar 中的实现。 - user253751
1
请参见 https://dev59.com/JmIj5IYBdhLWcg3ws3Jf。 - Eran
1
为什么不阅读教程,而只是提取示例代码呢? - Holger
2个回答

7
当你有一个实现多个接口的类,并且这些接口包含具有相似方法签名的方法(例如,您的startEngine方法)。
为了知道您所引用的方法,您需要执行以下操作:
yourInterface.super.method();

你可以查看这个链接,它也解答了你的问题。
所以,你也可以这样做:
public class FlyingCar implements FlyCar, OperateCar{
    public int startEngine(EncryptedKey key) {
        return FlyCar.super.startEngine(key);
    }
}

或者这个:

public class FlyingCar implements FlyCar, OperateCar{
    public int startEngine(EncryptedKey key) {
        return Operate.super.startEngine(key);
    }
}

无论如何,如果您仅从接口调用方法,则必须指定您正在调用方法的接口。
然而,这种情况只是一个例子。更有可能发生的是您会执行以下操作:
public int startEngine(EncryptedKey key) {
    // Custom implemenation...
}

这也是有效的。然而,如果你有两个接口具有相同签名的方法,那么你可能需要一个声明该方法的单一父接口,以及两个扩展它的子接口:

public interface Car {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Default implementation
};
}

public interface FlyCar extends Car {
    // Methods unique to FlyCar
}

public interface OperateCar extends Car {
    // methods unique to OperateCar
}

4
注意,"default"修饰符仅在Java 8及以上版本中可用。 - user3437460

5
我理解为,startEngine()没有在任何父类中定义,因此不应被称为驻留在其中。
是的,它已经定义了。例如,这是默认实现:
public interface OperateCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}

OperateCar.super.startEngine(key) 将执行默认实现。

如果没有默认实现,只有一个接口方法, 那么这个语句就没有意义了,因为接口不会包含实现,如下所示:

public interface OperateCar {
    // ...
    int startEngine(EncryptedKey key);
}

我也没有看到FlyingCar中超级类和两个接口之间的任何关系。

不确定你在问什么。 super是调用父接口实现的一种方式。没有super,就没有其他表达方式。


我知道有一个默认的实现,但是你是不是指它假设了一个默认的类(超类),在这个默认实现上进行了操作?这样逻辑上是有意义的。如果有一个默认的超类,那么我现在可以看到这两个接口和super之间的关系了。 - okey_on
3
“默认超类”这样的东西不存在,也不清楚你为什么会认为有这种东西。InterfaceName.super是从实现类调用非抽象接口方法的语法。就是这样。它看起来像这样因为Java语言设计人员这样规定了。这些非抽象接口方法被称为“默认方法”,因为它们需要使用该关键字标记为非抽象。这是为了保持与之前语言版本的兼容性,在那些版本中,“抽象”被隐含,即使没有指定,同时也是因为Java语言设计者这样规定了。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接