1

Java リフレクションを使用して可変アリティ メソッドを呼び出すと何が起こっているのかを理解したいと思います。簡単な方法があるとしましょう:

void doAllTheThings(Object ... things) {
  // ...which does something with all the things...
}

そして動的に呼び出したいので、リフレクションを通してメソッドを取得します:

Method doItAll = Superklass.getDeclaredMethod("doAllTheThings", Object[].class);

そして配列を渡します:

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(allTheThings);

さて、これは私の直感が理解したようにはうまくいかないようです。特に、IllegalArgumentExceptionこのように varargs を使用してメソッドを呼び出そうとすると、さまざまな色合いが得られるようです。

ここには明らかに欠けているものがあります。私の推測では、これは変数が varargs にマーシャリングされる方法に何らかの形で関連しています。同じ問題について話しているように見えるこの 4 年前のブログ投稿を見つけましたが、そこで「成功した」ケースを再現できません。ここで何が起こっているのかについて何か考えはありますか?

4

1 に答える 1

9

Object[][]この場合、 を渡す必要があります。

Object[] allTheThings = new Object[] { "abc", true, 15 };
doItAll.invoke(o, new Object[]{allTheThings});

その理由は、単一のthingsパラメーターがコンパイラによって type の単一のパラメーターに変換され、パラメーターの値を含む配列を取るためですObject[]invoke

より明確にするために、より多くのパラメーターを持つメソッドを検討してください。

void doMoreThings(Foo bar, Object ... things) { ... }

Object[] allTheThings = new Object[] { "abc", true, 15 };
doMore.invoke(o, new Object[]{new Foo(), allTheThings});

invokeそれ自体が varargs を取るように宣言されているため、コンパイラに外側の配列を作成させることができます。しかし、 を渡した場合、これは実行されません。これはObject[]、既に実行したと見なされるためです。したがって、その事実をコンパイラから隠してください。

doItAll.invoke(o, (Object)allTheThings);
doMore.invoke(o, new Foo(), allTheThings);

最初の行のキャストに注意してください。現在、コンパイラは配列が既に存在することを認識していないため、配列を作成します。2 行目では、これは必要ありません。コンパイラには他にチャンスがないからです。

編集doAllTheThings:メソッドを使用してクラスのインスタンスを渡さなかったため、コードはコンパイルされないことに注意してくださいinvoke(コードで名前を付けましoた)。

于 2012-02-27T20:02:27.887 に答える