インターフェースのデフォルト実装が継承した子クラスや子インターフェースから呼び出せることを今日知ったので調べてまとめることにしました。
呼び出し方法
結論から言うと、
親インターフェース名.super.メソッド名();
で呼び出せます。これ以降でいろんなパターンで試したことを書きます。
子クラスから親インターフェースのdefault実装を呼び出す
基礎。
普通にEclipseでdefault実装を持ってる実装クラスを作って「ソース」→「メソッドのオーバーライド実装」で保管されました。
Interface1.java
public interface Interface1 {
default void test() {
System.out.println("Interface1");
}
}
ImplA.java
public class ImplA implements Interface1 {
@Override
public void test() {
Interface1.super.test();
}
}
ImplA#testの実行結果は
Interface1
子インターフェースから親インターフェースのdefault実装を呼び出す
子クラスの方法と同じです。
Interface2.java
public interface Interface2 extends Interface1 {
@Override
default void test() {
Interface1.super.test();
}
}
ImplB.java
public class ImplB implements Interface2 {
}
ImplB#testの実行結果は
Interface1
子クラスから複数親インターフェースのdefault実装を呼び出す
なんでsuperの前にインターフェース名を書かないといけないのかが、
ここでやっと分かりました。
Interface3.java
public interface Interface3 {
default void test() {
System.out.println("Interface3");
}
}
ImplC.java
public class ImplC implements Interface1, Interface3 {
@Override
public void test() {
Interface1.super.test();
Interface3.super.test();
}
}
ImplC#testの実行結果は
Interface1
Interface3
子インターフェースから複数親インターフェースのdefault実装を呼び出す
public interface Interface4 extends Interface1, Interface3 {
@Override
default void test() {
Interface1.super.test();
Interface3.super.test();
}
}
public class ImplD implements Interface4 {
}
ImplD#testの実行結果は
Interface1
Interface3
ダメなパターン
型階層で2つ以上飛ばして、直接、superインターフェースのdefault実装は呼び出せない。
Interface5.java
public interface Interface5 extends Interface1 {
}
Interface6.java
public interface Interface6 extends Interface5 {
@Override
default void test() {
Interface1.super.test();//コンパイルエラー
}
}
下記はOK。
Interface7.java
public interface Interface7 extends Interface5 {
@Override
default void test() {
Interface5.super.test();
}
}
結果Interface1のデフォルト実装が呼び出される。
で、
extendsに入ってたらOKなのか?と思ってやってみたけど、下記もコンパイルエラー
public interface Interface8 extends Interface5, Interface1 {
@Override
default void test() {
Interface1.super.test();//コンパイルエラー
}
}
おまけ
親インターフェース名.super.メソッド名();
この書き方はインターフェースの継承・実装限定の記述っぽい。
普通のクラス継承で使うとコンパイルエラーになる。
Abs.java
public class Abs {
public void test() {
System.out.println("Abs1");
}
}
AbsImpl.java
public class AbsImpl extends Abs {
@Override
public void test() {
Abs.super.test();//コンパイルエラー
}
}
感想
複数親を呼び出せるのは便利!だけど使いこなせる気がしない。