Java 8が登場し始め、新しい機能をもたらしました。機能プログラミングにはLambda式(JSR-335)を使用します。今日は、Defender Methodとしても知られるLambda:Virtual Extensionの一部について説明します。この機能により、インターフェイス定義にメソッドを提供する方法を実装できます。たとえば、他の開発者がこれらの方法を再実装する必要がないように、既存のインターフェイス(リストやマップなど)の方法を定義できます。もちろん、Java 8は理論的に既存のライブラリと互換性があります。
仮想拡張法は、多発性継承特性をJavaにもたらしますが、それは複数の継承とは異なると主張していますが、仮想拡張方法は行動継承のために制限されています。おそらく、この機能を通して多発性継承の影を見ることができます。ただし、インスタンス状態の継承をシミュレートできます。次の記事では、Mixinを介した状態の継承について詳しく説明します。
Mixinに混合されたものは何ですか?
ミキシングは、主に複数のクラスをコンテキストに追加するために使用されます。たとえば、「馬」を示すクラスがある場合、このクラスをインスタンス化して「馬」の例を作成し、「ガレージ」と「庭」のように継承することで拡張できます。
Val Myhouse =庭のあるガレージ付きの新しい家
Mixin継承は特定の仕様ではありません。これは、既存のカテゴリにさまざまな機能を追加するために使用される方法にすぎません。 OOPでは、Mixinを使用して、クラスを通る読みやすさがあります。
たとえば、PythonのSocketServerモジュールには、MixinがマルチプロセスをサポートするUDPおよびTCPサービスを含む4つのサービス、およびマルチスレッドをサポートするUDPおよびTCPサービスを使用して、Mixinメソッドがあります。
クラスforkingpserver(forkingmixin、udpserver):passclass forkingtcpserver(forkingmixin、tcpserver):pass class class threadingudpserver(threadmixin):passclass threadingtcpserver(threadingmixin、tcpserver):パスパス
仮想拡張法とは何ですか?
Java 8は、パブリックディフェンダーメソッドとも呼ばれる仮想拡張の概念を紹介します。
Vemは、Javaインターフェイスのデフォルトの方法を使用することを目指しています。 Hibernateのようなこのような3番目のパーティライブラリは、いくつかのデフォルトの方法を提供しているため、これらのコレクションAPIのすべての方法を繰り返す必要はありません。
以下は、インターフェイス内のメソッドを定義する方法の例です。
パブリックインターフェイスコレクション<t> reding <t> {<r> collection <r>フィルター(Predicate <t> p)デフォルト{<t> collectss;}}}}}
Java 8の混合シミュレーション
今、私たちはVEMを通じて混合効果を達成するようになりますが、事前に警告は次のとおりです。職場で使用しないでください!
以下の実装は安全ではなく、メモリ漏れの問題があり、これはクラスで定義した方法に依存します。
まず、メソッド(シミュレートされた状態豆)の定義を定義し、メソッドを提供します。
public interface switchablemixin {boolean isactivated()default {return switchables.isactivated(this);} void setactivated(boolean activity)fault {switchables.setactivated(this、activated);}}}}
次に、インスタンスとステータスの関連付けを保存するためのマップインスタンスを含むツールクラスを定義します。
パブリティクラスのスイッチブル{プライベートスタティックマップ<switchablevicestate> switch_states = public static isactivated(switchablemixin device {switchableevicestate stated_states.get(デバイス)。アクティビティ;} public void setactivated(switchablemixin device、boolean activated){switchablevicestate = switch_states.get(device); .activated = activated;} private static class switchabledevicestate {private boolean activated;}}
これは、国家の相続を強調するユースケースです。
プライベート静的クラスデバイス{} private static class devicea拡張デバイスを実装したスイッチアブアブルエミキシン{}プライベート静的クラスデバイスB拡張デバイスIMP Leater SwitchableMixin {}
「まったく違うもの」
上記の実装は正常であるように見えますが、OracleのJava言語アーキテクトのブライアンゲッツは、現在の実装が機能しないという質問をしてくれました(スレッドの安全性とメモリの漏れが解決されたと仮定します)
Interface fakeBrokenMixin {Static Map <fakeBrokenMixin、buckingMap = collections(new weakhashmap <fakebrokenmixin、string getname()default {return backingmap.get(this);} void name(string name){backingmap。 put(this、name);}} interface xはrunnable、fakebrekenmixin {} x makex(){> {system.println( "x");}; (); setname( "x2");
このコードは実行後に表示されると思いますか?
疑いの解決
一見すると、この実装コードに問題はありません。 Xは、getNameとsetNameにはデフォルトの定義が既にあるため、1つのメソッドのみを含むインターフェイスですが、実行可能なインターフェイスの実行方法はxのxインスタンスを生成してから、xインスタンスを生成し、提供できます。実行方法の実装。したがって、実行後にこのプログラムが必要な結果は次のとおりです。
x1x2
getNameメソッドの呼び出しを削除すると、実行結果は次のようになります。
myTest $ 1@30AE8764MYTEST $ 1@123ACF34
これらの2つの行は、MakeXメソッドの実行が2つの異なるインスタンスから来ていることを示しており、現時点では現在のOpenJDK 8が生成されます(ここではOpenJDK 8 24.0-B07を使用しています)。
いずれにせよ、現在のOpenJDK 8は、この問題を解決するために最終的なJava 8の動作を反映していません。
x2x2
GetNameメソッドを呼び出しない場合、表示されます。
mytest $ $ lambda $ 1@5506d44eamytest $ $ lambda $ 1@5506d4ea
各呼び出しMakeXメソッドは、同じ匿名の内部クラスのシングルインスタンスのようです。
コンパイル中、ラムダの表現は実際には完全な翻訳を受けていませんでした。この命令には、実行時にLABDA発現に関するすべての必要なメタ情報が含まれています。メソッド名、入力、出力タイプ、およびブートストラップと呼ばれるメソッドを含みます。 Bootstrapメソッドは、JVMがInvokeDynamic命令を実行すると、JVMがLambda MetaFactoryメソッドを特定のブートストラップで調整するために使用されます。
今すぐ質問に戻ると、ラムダ式はプライベート静的メソッドに変わりました() - > {system.out.println( "x");}はmytestに転送されました。
private static void lambda $ 0(){system.out.println( "x");}
JavapカウンターコンパイルデバイスでPrivateパラメーターを使用し、この方法を見ることができる場合は、-Cパラメーターを使用して、より完全な変換を表示することもできます。
プログラムを実行すると、JVMはLambda MetaFactoryメソッドに電話して、Invokedynamicの指示を説明しようとします。この例では、MakeXが初めて呼び出された場合、Lambda MetaFactoryメソッドはXのインスタンスを生成し、Xのインスタンスがこのインスタンスに保存されますメモリでは、2回目の呼び出しのインスタンスは初めてと同じです。
修理しましたか?解決策はありますか?
この問題に対する直接的な修復や解決策はありません。 OracleのJava 8プログラムDefaults-XDlambDatomethodは、このパラメーターがJVM仕様の一部ではないため、異なるサプライヤーとJVMの実装は異なります。ラムダの表現の場合、期待できる唯一のことは、クラスにインターフェイス方法を実装することです。
その他の方法
これまでのところ、Mixinの模倣はJava 8と互換性がありませんが、複数の継承と任命を通じて複数のサービスを追加することは依然として可能です。この方法は、仮想フィールドパターン(仮想フィールドモード)です。
だから、私たちの切り替え可能を見てください。
インターフェイススイッチ可能{boolean isactive();
切り替え可能なインターフェイスが必要であり、スイッチ可能な実装に戻るための追加の抽象化方法を提供します。統合されたメソッドには、デフォルトの定義が含まれています。
Public Interface Switchableは、switchable getSwitchable();
次に、完全な切り替え可能な実装を作成します。
パブリッククラスSwitchable ImplはSwitchableを実装します{private boolean active;
これは、仮想フィールドモードの例です。
パブリッククラスデバイス{}パブリッククラスdevicea拡張スイッチ可能式{プライベートスイッチ可能模様のimpl(); switchable getSwitchable(){return Switchable;}}
結論は
この記事では、2つの方法を使用して、Java 8の仮想拡張方法を介して複数のサービスを追加します。最初の方法は、インスタンス状態を保存するためにマップを使用します。これは、スレッドが安全ではなく、メモリ漏れの問題があるため、Java言語の実現に異なるJVMの実現に完全に依存します。別の方法は、仮想フィールドモードを使用して、抽象ゲッターを介して最終実装の例を返すことです。 2番目の方法は、より独立しており、より安全です。
Virtual Extensionメソッドは、この記事の新機能を主に詳細に紹介します。