如何调用接口中的默认方法?

public interface MyFun {

default String getName(){
    return "哈哈哈";
}

}

public interface MyInterface {


default String getName(){
    return "呵呵呵";
}

public static void show(){
    System.out.println("接口中的静态方法");
}

}

public class SubClass implements MyFun, MyInterface{

@Override
public String getName() {
    return MyInterface.super.getName();
}

}

看到这样的代码,MyInterface.super.getName();这块不太明白,为什么要 点super才能调getName呢? 为什么这么写?

阅读 5.2k
2 个回答

这里因为是实现的两个接口都有同名的default方法,所以需要指定使用哪一个接口的方法做为实现.
<interface>.super.<method> 是专门用于此场景的语法.

为什么不直接用<interface>.<method> 调用呢?
因为<interface>.<method>写法是用来调用static修饰的方法的,default方法并不是static方法,所以在此不适用.

方法执行的时候需要指定方法的签名,以便找到对应的方法执行。
跟你认为的一样,super指代父类的某某某.
增加一个抽象的父类:

public abstract class AbsBase {

    public String getName() {
        return "抽象类";
    }
}

修改下子类:

public class SubClass extends AbsBase implements MyInterface, MyFun {
    @Override
    public String getName() {
        super.getName();
        MyInterface.super.getName();
        MyFun.super.getName();

        return "";
    }

    public static void main(String[] args) {
        SubClass subClass = new SubClass();
        System.out.println(subClass.getName());
    }
}

反编译一下:

Compiled from "SubClass.java"
public class com.example.demo.test.SubClass extends com.example.demo.test.AbsBase implements com.example.demo.test.MyInterface,com.example.demo.test.MyFun {
  public com.example.demo.test.SubClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method com/example/demo/test/AbsBase."<init>":()V
       4: return

  public java.lang.String getName();
    Code:
       0: aload_0
       1: invokespecial #2                  // Method com/example/demo/test/AbsBase.getName:()Ljava/lang/String;
       4: pop
       5: aload_0
       6: invokespecial #3                  // InterfaceMethod com/example/demo/test/MyInterface.getName:()Ljava/lang/String;
       9: pop
      10: aload_0
      11: invokespecial #4                  // InterfaceMethod com/example/demo/test/MyFun.getName:()Ljava/lang/String;
      14: pop
      15: ldc           #5                  // String
      17: areturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #6                  // class com/example/demo/test/SubClass
       3: dup
       4: invokespecial #7                  // Method "<init>":()V
       7: astore_1
       8: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_1
      12: invokevirtual #9                  // Method getName:()Ljava/lang/String;
      15: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      18: return
}

在过去的版本,super一直指代 父类.Method 得到签名 Method com/example/demo/test/AbsBase.getName:()Ljava/lang/String;

而新特性需要指定default方法,看下default方法和父类普通方法的区别:

Compiled from "AbsBase.java"
public abstract class com.example.demo.test.AbsBase {
  public com.example.demo.test.AbsBase();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.String getName();
    Code:
       0: ldc           #2                  // String 抽象类
       2: areturn
}
Compiled from "MyFun.java"
public interface com.example.demo.test.MyFun {
  public java.lang.String getName();
    Code:
       0: ldc           #1                  // String 哈哈哈
       2: areturn
}

存放的位置确实是在接口中,这里如果需要使用接口中的方法,如果使用super.Method即会产生歧义,java不允许不确定的方法签名;

所以我认为这里增加接口前缀的方式区分签名方法,以得到明确的执行链接。{ 接口.super.Method。}

个人拙见。。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题