こんにちは、ハラジテリ!
ごく最近、多くの人が期待する
Java 7がリリースされました。 残念なことに、多くの人はイノベーションの構成に失望しました
。ProjectLambdaのような非常に期待されるさまざまなグッズが含まれていなかったからです。 しかし、まだ多くの革新があり、今日では、最も重要なものの1つで
あるDa Vinci Machine Projectについて説明します。これにより、JVMで動的言語をより効率的に使用できます。 より正確には、Da Vinci Machine Projectの一部である
メソッドハンドルを検討します。 私はまだ言語のこの部分の概念を完全に理解することができていませんが、ほとんどの人はなぜそれが必要なのか理解していません:)この記事では、Javaプログラマーがこれまでにない最大数の自転車に精通していない1つのユースケースを検討します。 もちろん、メソッドをオーバーロードし、インターフェイスでパラメーターを渡すことに関するものです。
Javaでは、どのオーバーロードメソッドを呼び出すかは、コンパイル段階で決定されることが知られています(たとえば、実行時に行われるC#とは対照的です)。 次のコードがあるとします:
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
class A { } class B extends A { } public class Test { public void call(A a) { System. out .println( "A" ); } public void call(B b) { System. out .println( "B" ); } public static void main( String [] argv) { A b = new B(); Test test = new Test(); test.call(b); } } * This source code was highlighted with Source Code Highlighter .
Javaルールに従って、
public void call(A a)
メソッドが呼び出され、それに応じて「A」が表示されます。これは、オブジェクトの実際のタイプが
B
であるため、奇妙に見えるかもしれません
B
必要なメソッドを呼び出すには、次のようにメソッドを呼び出すようにコードを書き換える必要があります。
- if (b instanceof B){
- test.call((B)b);
- }
*このソースコードは、 ソースコードハイライターで強調表示されました。
このアプローチには生命権がありますが、そのようなクラスが数十個ある場合、コードは見苦しくなり、一般的に重複が発生します。
Java 7は、この問題を解決するのに役立つツールを導入しました。言語レベルでなければ、少なくとも松葉杖のレベルではありません。 したがって、
java.lang.invoke
パッケージのクラスが役立ち
java.lang.invoke
。
MethodHandle
は、メソッドへの一種のポインターです。このことは、クロージャーとラムダ式で広く使用されます(正直なところ、すべてが最も簡単な方法で行われると思いました-ラムダは匿名クラスに変換され、終わりを処理します)。MethodType
メソッドのシグネチャ、つまり戻り値と入力パラメーターのリストを表します。MethodHandles
メソッドを操作するためのさまざまなユーティリティのクラス。MethodHandles
クラスはMethodHandles
クラスの一部であり、指定されたパラメーターを持つメソッドを検索するためのインターフェースを提供します。
だから、私たちは最も興味深いものに移ります-これがすべて私たちを助けるか。 これで、コードは次のようになります。
- import static java.lang.invoke.MethodHandles。*;
- import java.lang.invoke.MethodHandle;
- import java.lang.invoke.MethodType;
- クラス A {
- }
- クラス BはAを拡張します{
- }
- パブリック クラステスト{
- public void call(A a){
- システム out .println( "A" );
- }
- public void call(B b){
- システム out .println( "B" );
- }
- public static void main( String [] argv){
- A b = new B();
- テストテスト= 新しいテスト();
- {
- ルックアップルックアップ= lookup();
- MethodType mt = MethodType.methodType(void。Class、b.getClass());
- MethodHandle mh = lookup.findVirtual(Test。Class、 "call" 、mt);
- mh.invokeWithArguments(test、b);
- } catch (Throwable e){
- e.printStackTrace();
- }
- }
- }
*このソースコードは、 ソースコードハイライターで強調表示されました。
ここで何が起こるか見てみましょう。 27行目で、関数の「検索エンジン」を直接宣言します。 次に、28行目で、戻り値とパラメーターの型を宣言します。 戻り値の型が最初に
methodType
メソッドに渡され、次に検索するメソッドのパラメーターリストの型が渡されることに注意することが重要です。 30行目
MethodHandle
で、
Test
クラスのメソッドの検索結果を、名前
call
および戻り値の型と
mt
パラメーターと共に取得します。 31行目では、
test
オブジェクトで見つかったメソッドをパラメーター
b
呼び出して、画面に期待される「B」を確認します。
Lookup
クラスには、静的関数を検索するためのメソッドなど、まだかなりの数のメソッドがありますが、機能の研究は宿題として読者に残っています。