Java Nashorn--Part 5

4049 ワード

Nashornの高度な応用
Nashornは複雑なプログラミング環境であり、アプリケーションを導入するための強力なプラットフォームとして設計され、Javaとの相互運用性が高い.JavaScriptをJavaに統合するためのより高度な使用例を見てみましょう.Nashornで実装の詳細を確認することで、実装方法を把握します.
NashornからJavaを呼び出す
各JavaScriptオブジェクトは最後にJavaクラスのインスタンスとしてコンパイルされるため、NashornとJavaのシームレスな統合は不思議ではないかもしれませんが、タイプシステムと言語特性の面で大きな違いがあります.しかしながら、この統合を十分に利用するためのいくつかのメカニズムが依然として必要である.NashornからJavaクラスとメソッドに直接アクセスできることを示しました.たとえば、次のようになります.
$ jjs -Dkey=value
jjs> print(java.lang.System.getProperty("key"));
value

このサポートがNashornでどのように実現されているかをよく見てみましょう.
JavaClassとJavaPackage
Javaの観点から、java.lang.System.getProperty(「key」)式はjava.lang.Systemクラスの静的メソッドgetProperty()にアクセスする資格がある.JavaScript構文としては、Javaという識別子から始まる属性チェーンへのアクセスに非常に似ています.次の例を見てみましょう.
jjs> print(java);
[JavaPackage java]

jjs> print(java.lang.System);
[JavaClass java.lang.System]

したがってjavaはNashorn内の特定のオブジェクトがJavaシステム内のパケットにアクセスするために使用され、javaはJavaPackageのJavaScriptのタイプとして定義され、JavaクラスはJavaClassのJavaScriptのタイプとして定義され、任意の最上位パケットはパケットナビゲーションオブジェクトとして直接使用され、サブパケットはJavaScriptオブジェクトとして割り当てることができる.Javaクラスにアクセスするための簡単な構文を提供します.
jjs> var juc = java.util.concurrent;
jjs> var chm = new juc.ConcurrentHashMap;

ナビゲーションパッケージオブジェクトに加えて、Javaと呼ばれる別のオブジェクトがあります.その中には、その有用な方法があります.最も重要なのはJava type()メソッドであり、ユーザーがJavaタイプシステムを問合せ、javaクラスを取得できるようにします.例:
jjs> var clz = Java.type("java.lang.System");
jjs> print(clz);
[JavaClass java.lang.System]

このクラスが指定されたclasspathに含まれていない場合(たとえば、jjs選択-cpオプションで指定されている場合)、ClassNotFoundException例外が放出されます(jjsはRuntimeException例外として処理されます).
jjs> var klz = Java.type("Java.lang.Zystem");
java.lang.RuntimeException: java.lang.ClassNotFoundException:
  Java.lang.Zystem

ほとんどの場合、JavaScriptでJavaClassタイプはJavaのオブジェクトのように使用されます(それらは少し異なりますが、基本的にはNashornレベルのクラスの映像と考えられます).たとえば、JavaClassを使用してNashornから直接Javaイメージを作成できます.
jjs> var clz = Java.type("java.lang.Object");
jjs> var obj = new clz;
jjs> print(obj);
java.lang.Object@73d4cc9e

jjs> print(obj.hashCode());
1943325854

// Note that this syntax does not work
jjs> var obj = clz.new;
jjs> print(obj);
undefined

JavaScriptとJava Lambda式
JavaScriptとJavaの相互運用性は非常に深いレベルに達しています.JavaScript関数をJavaインタフェースの匿名実装(またはlambda式)として使用することもできます.たとえば、Callableインタフェースの一例としてJavaScript関数を使用します.このインタフェースには1つの方法call()しかありません.は、パラメータを必要とせずvoidを返します.Nashornでは、JavaScript関数をlambda式の実装として使用できます.
jjs> var clz = Java.type("java.util.concurrent.Callable");
jjs> print(clz);
[JavaClass java.util.concurrent.Callable]
jjs> var obj = new clz(function () { print("Foo"); } );
jjs> obj.call();
Foo

事実上、基本的にNashornではJavaScript関数とJava lambda式の間に違いはありません.Javaで見たように、関数は自動的に適切なタイプのオブジェクトに変換されます.JavaのExecutorServiceインタフェースを使用してスレッドプール上でNashornのJavaScriptコードを実行する方法を見てみましょう.
jjs> var juc = java.util.concurrent;
jjs> var exc = juc.Executors.newSingleThreadExecutor();
jjs> var clbl = new juc.Callable(function (){
  \java.lang.Thread.sleep(10000); return 1; });
jjs> var fut = exc.submit(clbl);
jjs> fut.isDone();
false
jjs> fut.isDone();
true

等価なJavaコードと比較して(Java 8のlambdas式を使用しても)、テンプレートコードの減少はかなり驚くべきものです.しかし、lambdaを使用する方法にはいくつかの制限があります.たとえば:
jjs> var fut=exc.submit(function (){\
java.lang.Thread.sleep(10000); return 1;});
java.lang.RuntimeException: java.lang.NoSuchMethodException: Can't 
unambiguously select between fixed arity signatures
[(java.lang.Runnable), (java.util.concurrent.Callable)] of the method
java.util.concurrent.Executors.FinalizableDelegatedExecutorService↵
.submit for argument types
[jdk.nashorn.internal.objects.ScriptFunctionImpl]

ここでの問題は、ExecutorServiceには、リロードされたsubmit()メソッドがあります.1つのメソッドパラメータはCallableで、もう1つのリロードされたメソッドパラメータはRunnableです.残念なことに、JavaScript関数は、lambda式を含む2つのタイプに変換するのに適しています.を選択します.実行時にどちらかを選択できますが、それらの間で選択できないため、「明示的に選択できない」というエラー・メッセージが表示されます.