web-dev-qa-db-ja.com

Java 8の抽象クラスとインターフェースの違いは何ですか?

In Java抽象クラスとインターフェースには微妙だが重要な違いがありました: デフォルトの実装 。抽象クラスはそれらを持つことができましたが、インターフェースはできませんでした。Java 8では、インターフェースのデフォルト実装が導入されています。つまり、これはもはやインターフェースと抽象クラスの重大な違いではないということです。

それで何ですか?

私が知る限り、残っている唯一の違いは(おそらくフードの効率性の下にあるものを除いて)、抽象クラスは従来のJava単一継承に従いますが、インターフェースは複数継承を持つことができます(または必要に応じて複数の実装)。これは別の質問に私を導きます-

新しいJava 8インターフェースは diamond Problem

64
David Grinberg

インターフェイスに状態を関連付けることはできません。

抽象クラスには、状態を関連付けることができます。

さらに、インターフェイスのデフォルトのメソッドを実装する必要はありません。そのため、この方法では、既存のコードを壊すことはありません。インターフェースが更新を受け取る間、実装クラスはそれを実装する必要がないからです。
その結果、最適ではないコードを取得する可能性がありますが、より最適なコードが必要な場合は、デフォルトの実装をオーバーライドすることが仕事です。

最後に、ダイアモンドの問題が発生した場合、コンパイラは警告を表示します。yoは、実装するインターフェイスを選択する必要があります。

ダイヤモンドの問題の詳細を表示するには、次のコードを検討してください。

_interface A {
    void method();
}

interface B extends A {
    @Override
    default void method() {
        System.out.println("B");
    }
}

interface C extends A { 
    @Override
    default void method() {
        System.out.println("C");
    }
}

interface D extends B, C {

}
_

ここでは、_interface D extends B, C_でコンパイラエラーが発生します。

interface D inherits unrelated defaults for method() form types B and C

修正は次のとおりです。

_interface D extends B, C {
    @Override
    default void method() {
        B.super.method();
    }
}
_

Bからmethod()を継承したい場合。
Dclassの場合も同様です。

Java 8、8)のインターフェイスと抽象クラスの違いをさらに示すために、次のTeamを検討してください。

_interface Player {

}

interface Team {
    void addPlayer(Player player);
}
_

理論的には、プレーヤーのリストなどにプレーヤーを追加できるように、addPlayerのデフォルトの実装を提供できます。
ちょっと待って...?
プレーヤーのリストを保存するにはどうすればよいですか?
答えは、デフォルトの実装を利用できる場合でも、インターフェースでそれを行うことはできないということです。

68
skiwi

非常に詳細な回答がいくつかありますが、少なくとも抽象クラスを含む非常に少数の正当化の1つとして私が考える1つのポイントが欠落しているようです

抽象クラスはprotectedメンバー(およびデフォルトの可視性を持つメンバー)を持つことができます。インターフェイスのメソッドは暗黙的にpublicです。

17
Marco13

インターフェイスに実行可能コードを含めることができるようになったため、抽象クラスの多くのユースケースがインターフェイスに引き継がれます。ただし、抽象クラスにはメンバー変数を含めることができますが、インターフェイスにはできません。

ダイヤモンドの問題は、両方のインターフェイスが同じシグネチャを持つ同じメソッドのデフォルトの実装を提供する場合に、クラスが2つのインターフェイスを実装できないようにすることで回避されます。

5
Philipp

ただし、Java 8ではインターフェースのデフォルト実装が導入されています。つまり、インターフェースと抽象クラスの重要な違いではなくなりました。

さらに重要な違いはほとんどありません。この投稿を参照してください:

Java 8 のデフォルトクラスと抽象クラスのインターフェイス

新しいJava 8インターフェースはダイヤモンドの問題をどのように回避しますか?

ケース1:同じdefaultメソッドを持つ2つのインターフェースを実装しているため、実装クラスの競合

interface interfaceA{
    default public void foo(){
        System.out.println("InterfaceA foo");
    }
}
interface interfaceB{
    default public void foo(){
        System.out.println("InterfaceB foo");
    }
}
public class DiamondExample implements interfaceA,interfaceB{
    public void foo(){
        interfaceA.super.foo();
    }
    public static void main(String args[]){
        new DiamondExample().foo();
    }
} 

上記の例は以下のアウトアウトを生成します:

InterfaceA foo

ケース2:基本クラスを拡張し、デフォルトのメソッドでインターフェースを実装しています。コンパイラはダイヤモンドの問題を解決します。最初の例のように解決する必要はありません。

interface interfaceA{
    default public void foo(){
        System.out.println("InterfaceA foo");
    }
}

class DiamondBase {
    public void foo(){
        System.out.println("Diamond base foo");
    }
}

public class DiamondExample extends DiamondBase implements interfaceA{

    public static void main(String args[]){
        new DiamondExample().foo();
    }
}

上記の例では、以下の出力が生成されます。

Diamond base foo
4
Ravindra babu