Categories: Java

【Java入門】インターフェースの多重継承による菱形継承(ダイヤモンド継承)問題とは

ダイヤモンド継承でコンパイルエラーになる例

同じシグニチャを持つ複数のインターフェースをimplementsした場合、コンパイルエラーになります。

ifParent.java

public interface ifParent {
    default void X(){
        System.out.println("interfaseParent");
    }
}

ifA.java

public interface ifA extends ifParent{
    @Override
    default void X(){
        System.out.println("interfaseA");
    }
}

ifB.java

public interface ifB extends ifParent{
    @Override
    default void X(){
        System.out.println("interfaseB");
    }
}

classC.java

public class classC implements ifA ,ifB {   //ここでコンパイルエラーになる。
    public static void main(String[] args) {
        classC c = new classC();
        c.X();
    }
}

上記のソースをクラス図で表現すると以下のとおりです。

classCがifAとifBをimplementsしたタイミングでコンパイルエラーになります。
これはclassCから見た場合、ifAとifBが同階層にあり、両者ともdefaultメソッドをOverrideしているためです。
これを防ぐには以下のようにclassCでXメソッドをOverrideする必要があります。

classC.java

public class classC implements ifA ,ifB {
    public static void main(String[] args) {
        classC c = new classC();
        c.X();  //classC
    }
    @Override
    public void X(){
        System.out.println("classC");
    }
}

ダイヤモンド継承でコンパイルエラーにならない例

複数のインターフェースが同階層にあってもメソッドが異なる階層(距離が離れている場合)近いほうのメソッドが呼ばれるため、コンパイルエラーになりません。

ifParent.java

public interface ifParent {
    default void X(){
        System.out.println("interfaseParent");
    }
}

ifA.java

public interface ifA extends ifParent{
   @Override
   default void X(){
       System.out.println("interfaseA");
   }
}

ifB.java

public interface ifB extends ifParent{
}

classC.java

public class classC implements ifA ,ifB {
   public static void main(String[] args) {
       classC c = new classC();
       c.X();  //interfaseA
   }
}

上記ソースをクラス図で表現すると以下のとおり。

ダイヤモンド継承でコンパイルエラーになる例との違いはifBでOverrideしていない点。
より近い方でOverrideしたifAのXメソッドが呼ばれます。


以上で記事の解説はお終い!

もっとJavaやSpringを勉強したい方にはUdemyがオススメ!同僚に差をつけよう!

shiakisudev