デフォルトの方法があるのはなぜですか?
Java 8はリリース期間が延期されていますが、Lambdasの式が最終的にリリースされるとサポートされると確信しています。 前述のように、私たちは以前にこのテーマについて多くを議論しましたが、Lambdasの表現はJava 8のゲームルールの唯一の変更ではありません。
Java 8がリリースされており、Lambdaが含まれているとします。これで、Lambdaを使用する予定です。
list <?> list = ... list.faceach(…);
foreachの定義は、java.util.listまたはjava.util.collectionで見つけることができません。通常、JDKの関連するインターフェイスに新しいメソッドと実装を追加するソリューションです。ただし、リリースのリリースでは、既存の実装に影響を与えずに、インターフェイスに新しいメソッドを追加することは不可能です。
したがって、LambdaがJava 8で使用されている場合、順方向の互換性のためにコレクションライブラリに使用することはできません。
上記の理由により、新しい概念が導入されました。通常、防御方法である仮想拡張法をインターフェイスに追加できるように、ステートメントの動作のデフォルトの実装を提供できるようになりました。
簡単に言えば、Javaインターフェイスがメソッドを実装できるようになりました。デフォルトメソッドの利点は、インターフェイスの実装を破壊せずにインターフェイスに新しいデフォルトメソッドを追加できることです。
私の意見では、これは毎日使用される一種のJava特性ではありませんが、ラムダを使用してラムダを自然に使用することができます。
最も単純な例
最も簡単な例を見てみましょう:インターフェイスA、ClazzクラスはインターフェイスAを実装しています。
パブリックインターフェイスa {default void foo(){system.out.println( "calling a.foo()");} public class class a {}ClazzクラスがFOO()メソッドを実装していない場合でも、コードをコンパイルできます。 FOO()メソッドのデフォルトの実装は、インターフェイスAで提供されています。
この例を使用してクライアントコード:
clazz clazz = new clazz();
複数の継承?
一般的な質問があります。デフォルトメソッドの新機能を最初に聞いたとき、クラスが2つのインターフェイスを実装し、同じ署名を使用してデフォルトのメソッドを定義します以前の例で:
パブリックインターフェイス{デフォルトvoid foo(){system.out.println( "calling a.foo()");このコードは次の理由をコンパイルできません。
Java:タイプAからBまでFOO()までのクラスClazzは、無関係なデフォルト値を継承します
これを修復するために、Clazzでは、紛争を書き直す方法を手動で解決する必要があります。
Public Class ClazzはA、B {public void foo(){}}}を実装しますしかし、独自の方法を実装する代わりに、インターフェイスAからデフォルトの実装メソッドを呼び出したい場合はどうすればよいですか?これは可能です、以下に示すように、aのfoo()を引用してください。
Public Class ClazzはA、B {public void foo(){a.super.foo();}}}}}を実装しています。今、私はこの最終的な解決策が好きだと確信することはできません。デフォルトメソッド仕様の最初のドラフトで宣言されているように、署名のデフォルトメソッドの実現よりも簡潔なものかもしれません。
パブリッククラスのClazzはA、B {public void foo()default a.foo;}を実装していますしかし、これは文法を変えますね。インターフェイスAとインターフェイスBが相互に競合する多くのデフォルトメソッドを定義し、すべてのインターフェイスAのデフォルトメソッドを使用して競合を解決することをいとわない場合?現在、私は紛争を次々と解決して、すべての紛争を書き直さなければなりません。これには、多くの作業が必要であり、多数のテンプレートコードを作成する必要があります。
紛争を解決する方法には多くの議論が必要であると推定しますが、作成者は避けられない災害を受け入れることを決定したようです。
本当の例
デフォルトの方法の実際の例は、JDK8の初期の袋にあります。コレクションのコレクション方法の例に戻ると、java.lang.iterableインターフェイスで、そのデフォルトの実装が次のとおりであることがわかります。
@functionalinterfacepublicインターフェイス<t> {iterator <t> iterator(); foreachは、java.util.function.consumer関数インターフェイスタイプのパラメーターを使用します。これにより、次のように、ラムダ式またはメソッド参照を渡すことができます。
リスト<?> list = ... list.faceach(system.out :: println);
メソッド呼び出し
デフォルトのメソッドが実際にどのように呼び出されているかを見てみましょう。この問題に慣れていない場合は、Javaバイトに関するRebel Labsを読むことに興味があるかもしれません。
クライアントコードの観点から見ると、デフォルトの方法は一般的な仮想メソッドのみです。したがって、名前は仮想拡張法です。したがって、インターフェイスとしてのデフォルトメソッドの簡単な例の場合、クライアントコードは、デフォルトメソッドが呼び出される場所でインターフェイスを自動的に呼び出します。
clazz = clazz.foo();
デフォルトメソッドの競合が解決された場合、デフォルトメソッドを変更してインターフェイスのいずれかを指定するとき、Invokespecialは特定の呼び出しのインターフェイス実装の実装を指定します。
パブリッククラスはA、B {public void foo(){a.super.foo();以下はJavapの出力です。
public void foo(); code:0:aload_01:invokespecial#2 // interfacemethod a.foo: /()v4:return:return
ご覧のとおり、Invokespecial命令は、インターフェイスメソッドfoo()を呼び出すために使用されます。 Bytecodeの観点から見ると、これはまだ新しいことです。なぜなら、インターフェイスを指すスーパーの代わりにクラス(親)を指すことによってのみメソッドを呼び出すことができるからです。
やっと…
デフォルトの方法は、Java言語の興味深いサプリメントです。デフォルトの式の主な目標は、標準のJDKインターフェイスを進化させることであり、Java 8のLambdas式を最終的に使用し始めると、スムーズな移行体験を提供します。誰が知っているか、将来的にはAPI設計でより多くのデフォルトのメソッドが表示されるかもしれません。