次のAPIを想定します。
package nashorn.test;
public class API {
public static void test(String string) {
throw new RuntimeException("Don't call this");
}
public static void test(Integer... args) {
System.out.println("OK");
}
}
次のNashorn JavaScriptスニペットは失敗します。
var API = Java.type("nashorn.test.API");
API.test(1);
最初のメソッドが2番目のメソッドの代わりに呼び出されます。これはNashornエンジンのバグですか?
記録として、この問題は以前にjOOQユーザーグループで報告されており、メソッドのオーバーロードと可変引数が頻繁に使用されており、この問題が多くの問題を引き起こす可能性があります。
これがボクシングに関係しているのではないかという疑惑があるかもしれません。そうではありません。私が行うときにも問題が発生します
public class API {
public static void test(String string) {
throw new RuntimeException("Don't call this");
}
public static void test(Integer... args) {
System.out.println("OK");
}
public static void test(MyType... args) {
System.out.println("OK");
}
}
そして:
public class MyType {
}
その後:
var API = Java.type("nashorn.test.API");
var MyType = Java.type("nashorn.test.MyType");
API.test(new MyType());
Nashornのオーバーロード解決メカニズムを作成した人として、私は常に人々が遭遇するコーナーケースに魅了されています。良くも悪くも、これが最終的に呼び出される方法は次のとおりです。
Nashornのオーバーロードメソッドの解決は、Java言語仕様(JLS)にできるだけ似ていますが、JavaScript固有の変換も可能です。JLSによると、オーバーロードされた名前に対して呼び出すメソッドを選択する場合、適用可能な固定アリティメソッドがない場合にのみ、可変アリティメソッドを呼び出すことができます。通常、Java test(String)
からの呼び出しは、による呼び出しに適用できないint
ため、test(Integer...)
メソッドが呼び出されます。ただし、JavaScriptは実際には数値から文字列への暗黙的な変換を許可するため、適用可能であり、変数アリティメソッドの前に考慮されます。したがって、観測された動作。Arityは非変換よりも優先されます。追加した場合test(int)
メソッドは、固定されたアリティであり、文字列よりも具体的であるため、文字列メソッドの前に呼び出されます。
メソッドを選択するためのアルゴリズムを変更する必要があると主張できます。Nashornプロジェクト以前から(私がDynalinkを独自に開発していた頃から)、これについては多くの考えがなされてきました。現在のコード(Nashornが実際に構築しているDynalinkライブラリに組み込まれている)はJLSに準拠しており、言語固有の型変換がない場合、Javaと同じメソッドが選択されます。ただし、型システムの緩和を開始するとすぐに、物事は微妙に変化し始めます。それを緩和するほど、それらは変化し(JavaScript は大幅に緩和されます)、選択アルゴリズムへの変更には他にもいくつかの変化があります。誰かが遭遇する奇妙な振る舞い…それはただリラックスした型システムに付属しているだけだと思います。例えば:
test(String)
、int
パラメーターに適用可能と見なされないように強制する場合)、一部のJS開発者は、プログラムを歪めてStringメソッドを呼び出す必要があると感じます(たとえば、文字列であることtest(String(x))
を確認するx
など)。ご覧のとおり、私たちが何をしても、他の何かが苦しみます。オーバーロードされたメソッドの選択は、JavaとJSの型システムの間の狭い領域にあり、ロジックの小さな変更にも非常に敏感です。
最後に、オーバーロードの中から手動で選択する場合、引数の位置にあるパッケージ名の潜在的なメソッドシグネチャにあいまいさがなければ、非修飾の型名に固執することもできます。
API["test(Integer[])"](1);
java.lang.
プレフィックスも必要ありません。APIを作り直さない限り、構文上のノイズが少し軽減される可能性があります。
HTH、アッティラ。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加