インターフェースで定義されたメソッドの「デフォルト」実装とは何ですか?


91

コレクションインターフェイスで、removeIf()その実装を含むという名前のメソッドを見つけました。

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

インターフェイスでメソッド本体を定義する方法があるかどうか知りたいですか?キーワードと
は何defaultですか?



回答:


162

https://dzone.com/articles/interface-default-methods-javaから

Java 8には、「デフォルトメソッド」または(Defenderメソッド)の新機能が導入されています。これにより、開発者はこれらのインターフェースの既存の実装を壊すことなく、インターフェースに新しいメソッドを追加できます。これは、具象クラスがそのメソッドの実装を提供できない場合にデフォルトとして使用するインターフェース定義実装を可能にする柔軟性を提供します。

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

新しい機能について初めて聞いたときに、デフォルトの方法についてよく聞かれる質問が1つあります。

クラスが2つのインターフェースを実装し、両方のインターフェースが同じシグネチャを持つデフォルトのメソッドを定義する場合はどうなりますか?

この状況を説明する例:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

このコードはコンパイルに失敗し、次の結果になります。

java: class Clazz inherits unrelated defaults for foo() from types A and B

これを修正するには、Clazzで、競合するメソッドをオーバーライドして手動で解決する必要があります。

public class Clazz implements A, B {
    public void foo(){}
}

しかし、独自の実装ではなく、インターフェースAからメソッドfoo()のデフォルト実装を呼び出したい場合はどうでしょうか。

次のようにA#foo()を参照することができます。

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}

18
ありがとう、本当に良い博覧会。私が質問する前に、あなたは私の質問にすべて答えました。
ジェフハッチンズ

代わりに抽象を使用しないのはなぜですか?
Astolfo Hoscher

1
@AstolfoHoscher 1つのクラスしか拡張できませんが、複数のインターフェースを実装できます。
チャールズウッド

49

これらのメソッドは、デフォルトメソッドと呼ばれます。デフォルトのメソッドまたはDefenderメソッドは、Java 8で新しく追加された機能の 1つです。

これらは、具象クラスがそのメソッドの実装を提供しない場合に、インターフェースメソッドがデフォルトとして使用される実装を提供できるようにするために使用されます。

したがって、デフォルトのメソッドを持つインターフェースがある場合:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

次のクラスは完全に有効です。

public class HelloImpl implements Hello {

}

のインスタンスを作成する場合HelloImpl

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

役立つリンク:


それで、クラスがインターフェースを実装し、そのメソッドを実装しなくても大丈夫ですか?私が使用しているJava7に関する限り、これは許可されていません。
Aniket Thakur 2013

2
@AniketThakur。これはJava 8より前では許可されていません。この機能はJava 8でのみ追加されます。実装クラスでデフォルトメソッドの実装を提供しないようにすることができます。
Rohit Jain 2013

1
@PawanMishra。以前のコメントを参照してください。クラスを実装する際に、デフォルトのインターフェースメソッドの実装を提供する必要はありません。
Rohit Jain 2013

1
@PawanMishraあなたはそれを上書きすることができます。デフォルトの実装のみを使用する必要があるなどの制限はありません。
Aniket Thakur 2013

4
多重継承に戸惑うのをいよいよ避ける前進ステップ!
Xtreme Biker 14年

17

少し調べてみたところ、次のことがわかりました。お役に立てれば。

既存の問題

通常のインターフェイスメソッドは抽象として宣言され、インターフェイスを実装するクラスで定義する必要があります。これは、宣言されたすべてのメソッドを実装する責任を持つクラス実装者に「負担」をかけます。さらに重要なことに、これは「公開」後にインターフェイスを拡張することが不可能であることも意味します。それ以外の場合、すべての実装者は、ソースとバイナリ互換性を逆に壊して、実装を適応させる必要があります。

Java 8で採用されたソリューション

これらの問題に対処するために、JDK 8の新機能の1つは、既存のインターフェースをデフォルトのメソッドで拡張できることです。デフォルトのメソッドは宣言されているだけでなく、インターフェースでも定義されています。

注意すべき重要な点

  1. 実装者は、実装クラスにデフォルトメソッドを実装しないことを選択できます。
  2. 実装者は、通常の非最終クラスのメソッドをサブクラスでオーバーライドできるように、デフォルトのメソッドをオーバーライドできます。
  3. 抽象クラスは、デフォルトのメソッドを抽象として(再)宣言することもでき、サブクラスにメソッドの再実装を強制します(「再抽象化」と呼ばれることもあります)。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.