varargsパラメーターを指定してオーバーロードされたメソッドを呼び出すときのNashornのバグ

ルーカスエダー:

次の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 は大幅に緩和されます)、選択アルゴリズムへの変更には他にもいくつかの変化があります。誰かが遭遇する奇妙な振る舞い…それはただリラックスした型システムに付属しているだけだと思います。例えば:

  • varargsをfixargsと一緒に検討することを許可した場合、さまざまなアリティメソッド間の「より具体的な」関係を作成する必要があります。これは、JLSには存在せず、JLSとは互換性がなく、varargsの原因になります。それ以外の場合はJLSがfixargsの呼び出しを規定するときに呼び出されることがあります。
  • JSで許可された変換を許可しない場合(したがってtest(String)intパラメーターに適用可能と見なされないように強制する場合)、一部のJS開発者は、プログラムを歪めてStringメソッドを呼び出す必要があると感じます(たとえば、文字列であることtest(String(x))を確認するxなど)。

ご覧のとおり、私たちが何をしても、他の何かが苦しみます。オーバーロードされたメソッドの選択は、JavaとJSの型システムの間の狭い領域にあり、ロジックの小さな変更にも非常に敏感です。

最後に、オーバーロードの中から手動で選択する場合、引数の位置にあるパッケージ名の潜在的なメソッドシグネチャにあいまいさがなければ、非修飾の型名に固執することもできます。

API["test(Integer[])"](1);

java.lang.プレフィックスも必要ありませんAPIを作り直さない限り、構文上のノイズが少し軽減される可能性があります。

HTH、アッティラ。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

C ++の継承:オーバーライドされたときに仮想メソッドを呼び出す

分類Dev

複数のオーバーロードとデフォルトパラメータを使用して特定の基本メソッドを呼び出す

分類Dev

ジェネリック型パラメーターを持つメソッドと非ジェネリックパラメーターを持つメソッドがある場合、Javaはどのオーバーロードされたメソッドを呼び出すかをどのように決定しますか?

分類Dev

スーパークラス参照を使用してオーバーロードされた継承されたメソッドを呼び出す

分類Dev

nullパラメータを持つオーバーロードされたメソッドを呼び出すことは良い習慣ですか?

分類Dev

オーバーライドされたメソッド内で元のメソッドを呼び出す方法

分類Dev

F#でパラメータタイプによってオーバーロードされたメソッドを呼び出す方法は?

分類Dev

パラメータとして指定されたC ++クラスメソッドを呼び出す方法は?

分類Dev

Javaライブラリのメソッドを呼び出すときにオーバーロードされた定義へのあいまいな参照

分類Dev

Mockito-Varargsパラメーターを使用してオーバーロードされたメソッドをモックする

分類Dev

オーバーロードされたメソッドの呼び出し

分類Dev

オーバーロードされたメソッドの呼び出しを正しく逆コンパイルできるJava Decompilerはありますか?

分類Dev

オーバーライドされたメソッド内の匿名の内部クラス内からスーパーメソッドを呼び出す

分類Dev

Javaラッパー:スーパーコンストラクターで呼び出されたメソッドをオーバーライドします

分類Dev

Javaメソッドのオーバーライド-パラメーターが使用されると親メソッドが呼び出されます

分類Dev

コンパイル時エラー:オーバーロードされたメソッドの呼び出しがあいまいです。どうして?

分類Dev

チェックされたラジオボタンのみをパラメータとして渡すメソッド呼び出しを作成します

分類Dev

メソッドをオーバーライドして基本型にキャストした後、どのメソッドが呼び出されますか?

分類Dev

パラメータとしてサブクラスを持つオーバーロードメソッドが、スーパークラスとして呼び出されるメソッドを持っている

分類Dev

キャッチされないエラー:初期化の前にプログレスバーのメソッドを呼び出すことはできません。メソッド 'value'を呼び出そうとしました

分類Dev

ScalaでKotlinのオーバーロードされたメソッドを呼び出す

分類Dev

Lispで別のオーバーロードされたメソッドを呼び出す

分類Dev

Revealing PrototypePatternを使用してオーバーライドされたメソッドを内部的に呼び出す方法

分類Dev

抽象オーバーライドとして宣言されている基本メソッドを呼び出す方法

分類Dev

Javaのリフレクションを使用してオーバーライドされたインスタンスメソッドを呼び出す

分類Dev

Java:オーバーライドされたメソッドを呼び出すスーパーメソッドを呼び出す

分類Dev

スーパークラスのオーバーライドされたセッタープロパティを呼び出すことができません

分類Dev

パラメータがnullのメソッド呼び出しのオーバーロード

分類Dev

オーバーライドされた関数のパラメータ-operator()c ++を呼び出す

Related 関連記事

  1. 1

    C ++の継承:オーバーライドされたときに仮想メソッドを呼び出す

  2. 2

    複数のオーバーロードとデフォルトパラメータを使用して特定の基本メソッドを呼び出す

  3. 3

    ジェネリック型パラメーターを持つメソッドと非ジェネリックパラメーターを持つメソッドがある場合、Javaはどのオーバーロードされたメソッドを呼び出すかをどのように決定しますか?

  4. 4

    スーパークラス参照を使用してオーバーロードされた継承されたメソッドを呼び出す

  5. 5

    nullパラメータを持つオーバーロードされたメソッドを呼び出すことは良い習慣ですか?

  6. 6

    オーバーライドされたメソッド内で元のメソッドを呼び出す方法

  7. 7

    F#でパラメータタイプによってオーバーロードされたメソッドを呼び出す方法は?

  8. 8

    パラメータとして指定されたC ++クラスメソッドを呼び出す方法は?

  9. 9

    Javaライブラリのメソッドを呼び出すときにオーバーロードされた定義へのあいまいな参照

  10. 10

    Mockito-Varargsパラメーターを使用してオーバーロードされたメソッドをモックする

  11. 11

    オーバーロードされたメソッドの呼び出し

  12. 12

    オーバーロードされたメソッドの呼び出しを正しく逆コンパイルできるJava Decompilerはありますか?

  13. 13

    オーバーライドされたメソッド内の匿名の内部クラス内からスーパーメソッドを呼び出す

  14. 14

    Javaラッパー:スーパーコンストラクターで呼び出されたメソッドをオーバーライドします

  15. 15

    Javaメソッドのオーバーライド-パラメーターが使用されると親メソッドが呼び出されます

  16. 16

    コンパイル時エラー:オーバーロードされたメソッドの呼び出しがあいまいです。どうして?

  17. 17

    チェックされたラジオボタンのみをパラメータとして渡すメソッド呼び出しを作成します

  18. 18

    メソッドをオーバーライドして基本型にキャストした後、どのメソッドが呼び出されますか?

  19. 19

    パラメータとしてサブクラスを持つオーバーロードメソッドが、スーパークラスとして呼び出されるメソッドを持っている

  20. 20

    キャッチされないエラー:初期化の前にプログレスバーのメソッドを呼び出すことはできません。メソッド 'value'を呼び出そうとしました

  21. 21

    ScalaでKotlinのオーバーロードされたメソッドを呼び出す

  22. 22

    Lispで別のオーバーロードされたメソッドを呼び出す

  23. 23

    Revealing PrototypePatternを使用してオーバーライドされたメソッドを内部的に呼び出す方法

  24. 24

    抽象オーバーライドとして宣言されている基本メソッドを呼び出す方法

  25. 25

    Javaのリフレクションを使用してオーバーライドされたインスタンスメソッドを呼び出す

  26. 26

    Java:オーバーライドされたメソッドを呼び出すスーパーメソッドを呼び出す

  27. 27

    スーパークラスのオーバーライドされたセッタープロパティを呼び出すことができません

  28. 28

    パラメータがnullのメソッド呼び出しのオーバーロード

  29. 29

    オーバーライドされた関数のパラメータ-operator()c ++を呼び出す

ホットタグ

アーカイブ