JAva 8のデフォルトメソッド

3378 ワード

デフォルトの方法は何ですか?
デフォルトのメソッドはdefault修飾子によって修飾され、クラスで宣言された他のメソッドのようにメソッドボディが含まれます.Java 8に新しく追加されたコンピテンシーです.
デフォルトの方法は何ができますか?
オプションの方法
デフォルトメソッドの主な適用シーンは、APIを定義する上で、一時的にインタフェースにメソッドを追加することによる気まずい思いを避けることができます.
身近な例を挙げる.例えばAndroidをアップグレードするときにインタフェースに方法を追加しましたが、方法はあまり使われていません.アップグレードするときは、この方法を実装して空の実装を追加したり、サポートされていない異常を投げ出したりしなければなりません.しかし、今ではデフォルトの方法があります.このシーンではAndroidはデフォルトの方法を書くことができます.私たちが使用しないインタフェースの方法を実現する必要はありません.
要するに,必ずしも実現しなければならないインタフェース手法ではなく,実現時に意図的に白状することを避けることができる.
関数インタフェース
前述したように,関数式インタフェースは抽象的な方法のみを含むインタフェースである.この言葉は以前はあまり考慮する必要はありませんでしたが、今ではデフォルトの方法があれば違います.デフォルトメソッドは抽象メソッドではないので、いくつかのデフォルトメソッドは影響しません.実際、現在の関数インタフェースPredicate、Function、Comparatorにもデフォルトの方法が導入されています.
動作のマルチ継承
その年にJavaを学んだとき、継承を学んだ位置に特に注意しなければならないのは、JavaがC++のように行為の多継承をサポートしていないことだ.今は違います.デフォルトの方法があれば、インタフェースに実装を書くことができます.このとき、複数のインタフェースを実現するには、私たちは自然にそれぞれのインタフェースの能力を持っています.
これにより,独立した能力を解決できる汎用コードをインタフェースに抽出し,必要な能力をデフォルトの方法で実現できる.これらの能力を使いたいときにインタフェースを実現すればいいです.この方式はテンプレート設計モードと似ている.
デフォルトメソッドに問題があるか
メソッド名の競合
デフォルトメソッドの前に、重複するメソッドのある2つのインタフェースを実装すれば、重複するインタフェースメソッドを1つに実装すればよい.しかし、デフォルトメソッドがあり、2つのインタフェースに同じ名前のデフォルトメソッドがある場合、この2つのインタフェースを同時に実装するときにどのメソッドを使用するかを選択します.このような状況は極めて低い可能性がありますが、このような問題を処理するルールが必要です.
問題解決の3つのルール
  • クラスのメソッドの優先度が最も高い.クラスまたは親クラスで宣言されたメソッドの優先度は、デフォルトメソッドとして宣言されたメソッドよりも高いです.
  • 第1条に基づいて判断できない場合、サブインタフェースの優先度が最も高い:関数署名とともに、最も具体的な実装のデフォルトメソッドを持つインタフェースを優先的に選択する.すなわち、BがAを継承している場合、BはAよりも具体的である.
  • 最後に、複数のインタフェースを継承したクラスが、所望のメソッドを上書きして呼び出すことによって、表示される選択がどのデフォルトメソッドを使用するかを判断できない場合がある.

  • 以上の3つのルールはすべての衝突の問題を処理することができ、以下に例を挙げて説明します.
    例1
    public interface A {
        default void hello() {
            System.out.println("A");
        };
    }
    
    public interface B extends A{
        @Override
        default void hello() {
            System.out.println("B");
        };
    }
    
    public class D implements A {
        //   hello()
    }
    
    public class C extends D implements B, A {
        public static void main(String... args) {
            new C().hello();
        }
    }
    
    

    上記のコードを見ると、まずルール1に従って、クラスで宣言されたメソッドには最高の権限がありますが、クラスDではデフォルトのメソッドhelloは実装されていません.ここでクラスDがhelloを実現すれば,彼は最高の優先度を持つ.次にルール2を見て、誰がもっと具体的なのかを見て、BはAを継承しているので、Bはもっと具体的なので、印刷されたのは「B」です.
    例2
    先着コード
    public interface A {
        default void hello() {
            System.out.println("A");
        };
    }
    
    public interface B {
        default void hello() {
            System.out.println("B");
        };
    }
    public class C implements B, A {
        public static void main(String... args) {
            new C().hello();
        }
    }
    

    この場合、何が印刷されますか?答えはコンパイルエラーを投げ出すことです.誰がもっと具体的なのか判断できないからです.このときは明示的に呼び出す必要があります.
    具体的な方法は、実装方法を上書きし、方法で明示的に呼び出すことである.表示呼び出しについては、Java 8に導入された新しい構文X.super.m(...),ここでXは、呼び出したいmメソッドが存在する親インタフェースです.たとえば、上記の問題は、次のコードのように呼び出しを表示することができます.
    public class C implements B,A {
    
        public static void main(String... args) {
            new C().hello();
        }
        
        @Override
        public void hello() {
            A.super.hello();
        }
    }
    

    最後に
    余計なことを言う
    今ではインタフェースにも書くことができますが、抽象クラスとインタフェースには違いがあります.まずクラスは1つの抽象クラスしか継承できませんが、複数のインタフェースを実現できます.次に抽象クラスは変数を定義することができ、インタフェースはできません.
    個人的にはデフォルト関数の最大の意味はAPIの作成に便利で、インタフェースが実現しなければならない苦痛を避けることだと思います.
    最後に
    仕事が終わる!なぜStreamをスキップしたのか聞かないでください.機能が強いので、書くのが大変です.みんなの討論を歓迎して意見を出します~~
    「Funny新青年」微信公衆番号へようこそ