为什么我们需要super关键字来调用默认接口方法?

时间:2018-02-05 14:37:02

标签: java oop interface super

在下面的代码中,当我有一个实现两个具有相同默认方法签名的接口的类时,它要求我覆盖它。但是在overriden方法中为什么我必须使用super keyWord来调用默认方法。

package practice;



interface interA{

public default void AImp(){
    System.out.println("Calling Aimp from interA");
}
}


interface interB{

public default void AImp(){
    System.out.println("Calling Aimp from interB");
}
}

public class Practice implements interA,interB {

public static void main(String[] args) {


Practice inter = new Practice();

    inter.AImp();

}

@Override
public void AImp() {

    interA.super.AImp();
}
}

我可以使用以下代码执行相同的操作:

@Override
public void AImp() {
    interA inter = new Practice();
    inter.AImp();
}

4 个答案:

答案 0 :(得分:1)

基于@MalteHartwig的评论。

直接引自Java tutorial

  

如果两个或多个独立定义的默认方法发生冲突,或者a   默认方法与抽象方法冲突,然后与Java冲突   编译器产生编译器错误。你必须明确覆盖   超类型方法。

     

考虑一下现在可以飞行的计算机控制汽车的例子。   您有两个提供默认值的接口(OperateCar和FlyCar)   同一方法的实现,(startEngine):

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

public interface FlyCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}
     

实现OperateCar和FlyCar的类必须覆盖   方法startEngine。您可以调用任何默认值   使用super关键字实现。

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

super之前的名称(在本例中为FlyCar或OperateCar)必须   指定义或继承默认值的直接超接口   对于调用的方法。这种形式的方法调用不是   限制区分多个实现的接口   包含具有相同签名的默认方法。你可以使用   super关键字在两个类中调用默认方法   接口

答案 1 :(得分:0)

您没有覆盖,您已使用相同的命名方法实现了接口。更确切地说,您已经实现了两个接口,无论您想在AImpl中运行什么代码,都必须解析diamond problem。 IDE要求您覆盖钻石层次结构的因为。提供代码后, interA.super 将用作导航到所需代码的方式。

答案 2 :(得分:0)

练习类实现了2个接口。 即InterA和InterB。 使用的习语指定了您希望调用的两种默认方法中的哪一种。 这是因为2种方法具有相同的签名。

但是,当您覆盖练习类上的签名时:

package practice;

interface InterA {

    public default void AImp() {
        System.out.println("Calling Aimp from interA");
    }
}

interface InterB {

    public default void AImp() {
        System.out.println("Calling Aimp from interB");
    }
}

public class Practice implements InterA, InterB {

    public static void main(String[] args) {

        Practice inter = new Practice();

        inter.AImp();

    }

//    @Override
//    public void AImp() {
//
//        interA.super.AImp();
//    }
    @Override
    public void AImp() {
        InterA inter = new Practice();
        inter.AImp();
    }
}

你没有得到相同的结果。 你得到:

Exception in thread "main" java.lang.StackOverflowError
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)
at practice.Practice.AImp(Practice.java:35)

您通过InterA接口引用实践实例,该实例强制使用已实现的接口,该接口将再次实例化练习并调用AImp。这将以递归方式重复,直到抛出java.lang.StackOverflowError。

答案 3 :(得分:0)

实际上,超级一词的使用在这里令人困惑。正如@Basilevs指出的,每当一个类实现的两个接口的默认方法发生冲突时,都会导致编译错误(公平)。要消除此错误,该类必须提供其对该方法的实现,因此,编译器不再会对它将调用的方法感到困惑。

解决编译错误后的下一件事是如何绕过类本身提供的实现来调用接口的默认实现。为此,将使用已定义该方法的直接实现的超级接口的名称来调用该方法。

在上面的示例中,由@Ashraf Mulla发布,调用interB.super.AImp();。打印“从B调用AImp”,因为这是按照Java规范应该执行的操作。接口B是直接接口,具有AImp方法的实现,因此将被执行。

要进一步测试,还可以尝试使用扩展接口A和接口B的第三个接口,这将需要提供其AImp方法的重写实现来克服编译错误。如果一个类实现了所有三个接口(接口A,接口B和接口C扩展了A和B),则调用interA.super.Aimp,interB.super.Aimp将导致编译错误,并带有与interC一起调用的确切描述.super,它是具有方法定义的直接超级接口。