サーチ…


前書き

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

構文

  • パブリックのデフォルトvoid methodName(){/ * method body * /}

備考

デフォルトのメソッド

  • 既存のサブクラスで強制的に実装することなく、動作を導入するために、インタフェース内で使用できます。
  • サブクラスまたはサブインターフェースによってオーバーライドできます。
  • java.lang.Objectクラスのメソッドをオーバーライドすることはできません。
  • 複数のインタフェースを実装しているクラスが、それぞれのインタフェースから同じメソッドシグネチャを持つデフォルトメソッドを継承する場合は、(複数継承の解決の一環として)デフォルトメソッドでないかのように独自のインタフェースをオーバーライドして提供する必要があります。
  • 既存の実装を破ることなく動作を導入することを意図していますが、新しく導入されたデフォルトメソッドと同じメソッドシグニチャーを持つ静的メソッドを持つ既存のサブクラスは依然として破損します。しかし、スーパークラスにインスタンスメソッドを導入した場合でも、これは当てはまります。



静的メソッド

  • インターフェイス内で使用できます。主にデフォルトメソッドのユーティリティメソッドとして使用されます。
  • サブクラスまたはサブインターフェース(それらに隠されている)によってオーバーライドすることはできません。しかし、今でも静的メソッドの場合と同様に、各クラスまたはインタフェースは独自のものを持つことができます。
  • java.lang.Objectクラスのインスタンスメソッドをオーバーライドすることはできません(現時点ではサブクラスの場合も同様です)。



以下は、サブクラスとスーパークラスの相互作用を要約した表です。

- SUPER_CLASS-INSTANCE-METHOD スーパークラス静的メソッド
SUB_CLASS-INSTANCE-METHOD オーバーライド 生成 - コンパイル時エラー
SUB_CLASS-STATIC-METHOD 生成 - コンパイル時エラー 隠す



以下は、インタフェースと実装クラス間の相互作用を要約した表です。

- インタフェース初期化メソッドインターフェース静的メソッド
IMPL_CLASS-INSTANCE-METHOD オーバーライド 隠す
IMPL_CLASS-STATIC-METHOD 生成 - コンパイル時エラー 隠す

参考文献:

  • http://www.journaldev.com/2752/java-8-interface-changes-static-method-default-method
  • https://docs.oracle.com/javase/tutorial/java/IandI/override.html

デフォルトメソッドの基本的な使い方

/**
 * Interface with default method
 */
public interface Printable {
    default void printString() {
        System.out.println( "default implementation" );
    }
}

/**
 * Class which falls back to default implementation of {@link #printString()}
 */
public class WithDefault
    implements Printable
{
}

/**
 * Custom implementation of {@link #printString()}
 */
public class OverrideDefault
    implements Printable {
    @Override
    public void printString() {
        System.out.println( "overridden implementation" );
    }
}

次のステートメント

    new WithDefault().printString();
    new OverrideDefault().printString();

この出力を生成します:

default implementation
overridden implementation

デフォルトメソッド内の他のインタフェースメソッドへのアクセス

デフォルトメソッド内から他のインタフェースメソッドにアクセスすることもできます。

public interface Summable {
    int getA();

    int getB();

    default int calculateSum() {
        return getA() + getB();
    }
}

public class Sum implements Summable {
    @Override
    public int getA() {
        return 1;
    }

    @Override
    public int getB() {
        return 2;
    }
}

次の文は3を出力します:

System.out.println(new Sum().calculateSum());

デフォルトのメソッドは、インターフェイスの静的メソッドと一緒に使用することもできます。

public interface Summable {
    static int getA() {
        return 1;
    }

    static int getB() {
        return 2;
    }

    default int calculateSum() {
        return getA() + getB();
    }
}

public class Sum implements Summable {}

次のステートメントは、3を出力します。

System.out.println(new Sum().calculateSum());

オーバーライドされたデフォルトメソッドにクラスを実装することからアクセスする

クラスでは、 super.foo()はスーパークラスのみを検索します。 superインタフェースからデフォルトの実装を呼び出す場合は、インタフェース名Fooable.super.foo() superを修飾する必要があります。

public interface Fooable {
    default int foo() {return 3;}
}

public class A extends Object implements Fooable {
    @Override
    public int foo() {
        //return super.foo() + 1; //error: no method foo() in java.lang.Object
        return Fooable.super.foo() + 1; //okay, returns 4
    }
}

なぜデフォルトメソッドを使用するのですか?

簡単な答えは、既存の実装を破ることなく既存のインターフェースを進化させることができるということです。

たとえば、20年前に公開したSwimインターフェイスがあります。

public interface Swim {
    void backStroke();
}

私たちはすばらしい仕事をしてくれました。私たちのインターフェースは非常に普及しています。世界中の多くの実装があり、ソースコードを管理することはできません。

public class FooSwimmer implements Swim {
    public void backStroke() {
         System.out.println("Do backstroke");
    }
}

20年後には、新しい機能をインターフェースに追加することに決めましたが、インターフェースが凍結されているように見えます。既存の実装を破るためです。

幸いJava 8では、 Defaultメソッドという新しい機能が導入されています。

Swimインターフェイスに新しいメソッドを追加できるようになりました。

public interface Swim {
    void backStroke();
    default void sideStroke() {
        System.out.println("Default sidestroke implementation. Can be overridden");
    }
}

現在、インタフェースの既存の実装はすべて機能します。しかし、最も重要なのは、新しく追加されたメソッドを独自の時間に実装できることです。

この変更の最大の理由の1つ、そしてその最大の用途の1つは、Java Collectionsフレームワークです。 Oracleは、Iterableを実装した既存のコードをすべて破棄することなく、既存のIterableインタフェースにforeachメソッドを追加できませんでした。デフォルトのメソッドを追加することで、既存のIterableの実装はデフォルトの実装を継承します。

クラス、抽象クラス、およびインターフェイスメソッドの優先順位

抽象宣言を含むクラス内の実装は、すべてのインタフェースのデフォルトよりも優先されます。

public interface Swim {
    default void backStroke() {
        System.out.println("Swim.backStroke");
    }
}

public abstract class AbstractSwimmer implements Swim {
    public void backStroke() {
        System.out.println("AbstractSwimmer.backStroke");
    }
}

public class FooSwimmer extends AbstractSwimmer {
}

次のステートメント

new FooSwimmer().backStroke();

生産する

AbstractSwimmer.backStroke

public interface Swim {
    default void backStroke() {
        System.out.println("Swim.backStroke");
    }
}

public abstract class AbstractSwimmer implements Swim {
}

public class FooSwimmer extends AbstractSwimmer {
    public void backStroke() {
        System.out.println("FooSwimmer.backStroke");
    }
}

次のステートメント

new FooSwimmer().backStroke();

生産する

FooSwimmer.backStroke

デフォルトメソッド多重継承の衝突

次の例を考えてみましょう。

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

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

同じシグニチャを持つdefaultメソッドfooを宣言する2つのインタフェースがありdefault

これらの両方のインタフェースを新しいインタフェースでextendしようとextendと、2つのインタフェースを選択する必要があります。なぜならJavaはこの衝突を明示的に解決する必要があるからです。

まず 、メソッドfooabstractと同じシグネチャで宣言すると、 AB動作がオーバーライドされます。

public interface ABExtendsAbstract extends A, B {
    @Override
    void foo();
}

class ABExtendsAbstractimplement ABExtendsAbstractは、 foo実装を提供する必要があります:

public class ABExtendsAbstractImpl implements ABExtendsAbstract {
    @Override
    public void foo() { System.out.println("ABImpl.foo"); }
}

それとも 、あなたは完全に新しい提供することができdefault実装を。また、クラスの実装からオーバーライドされたデフォルトメソッドにアクセスすることによって、 AおよびB fooメソッドのコードを再利用することもできます

public interface ABExtends extends A, B {
    @Override
    default void foo() { System.out.println("ABExtends.foo"); }
}

class ABExtendsimplement ABExtendsは、 foo実装を提供する必要はありnot

public class ABExtendsImpl implements ABExtends {}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow