Java反射:getMethod(String method, Object[].class) 不起作用

发布于 2024-10-27 08:03:43 字数 386 浏览 1 评论 0原文

我有以下代码:

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

public void invokeMyMethod() {
    Method s = this.getClass().getMethod("myMethod", Object[].class);
    Object[] ex = new Object[2];
    ex[0] = "hi";
    ex[1] = "there";
    s.invoke(this, ex);
}

我收到异常 java.lang.IllegalArgumentException:参数数量错误。怎么了?

I have the following code:

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

public void invokeMyMethod() {
    Method s = this.getClass().getMethod("myMethod", Object[].class);
    Object[] ex = new Object[2];
    ex[0] = "hi";
    ex[1] = "there";
    s.invoke(this, ex);
}

I'm getting the exception java.lang.IllegalArgumentException: wrong number of arguments. What's wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ペ泪落弦音 2024-11-03 08:03:43

您需要像这样调用该方法:

s.invoke(this, new Object[]{new Object[]{"hi", "there"}});

(...或使用 @Jon 的答案中的替代方法。)

当前代码失败的原因与 Java 中可变参数方法的实现方式有关。本质上,T1 xxx(T2...args)T1 xxx(T2[] args) 的语法糖。当您调用这些方法时,xxx(arg1, arg2, arg3)xxx(new T2[]{arg1, arg2, arg3}) 的语法糖。

在本例中,您尝试使用另一个具有相同数组基类型的可变方法来调用可变方法,并且代码有多种可能的解释。

当可变调用有两种可能的解释时,Java假设您正在尝试使用调用的“unsugared”版本而不是“sugared”版本。或者更准确地说,使用“加糖”解释当且仅当

  • 实际参数的数量不等于形式参数的数量,
  • 最后一个实际参数与最后一个形参的(数组)类型不兼容。

如果您感兴趣,JLS 中的 15.12 节中指定了此行为。 4.2.

所以......我的解决方案通过强制非可变解释并显式构造所需的数组来工作。 @Jon 的解决方案通过强制正确的可变解释来工作。

You need to call the method like this:

s.invoke(this, new Object[]{new Object[]{"hi", "there"}});

(... or use the alternative in @Jon's answer.)

The reason your current code fails is to do with the way that varadic methods are implemented in Java. Essentially, T1 xxx(T2... args) is syntactic sugar for T1 xxx(T2[] args). And when you call the methods, xxx(arg1, arg2, arg3) is syntactic sugar for xxx(new T2[]{arg1, arg2, arg3}).

In this case, you are trying to call a varadic method using another varadic method with the same array basetype, and there are multiple possible interpretations of the code.

When there are two possible interpretations of a varadic call, Java assumes that you are trying to use the "unsugared" version of the call instead of the "sugared" version. Or to be more precise, the "sugared" interpretation is used if and only if:

  • the number of actual arguments is not equal to the number of formal parameters, or
  • the last actual argument is NOT assignment compatible with the (array) type of the last formal parameter.

If you are interested, this behaviour is specified in the JLS in section 15.12.4.2.

So ... my solution works by forcing the non-varadic interpretation and explicitly constructing the required array. @Jon's solution works by forcing the correct varadic interpretation.

浅黛梨妆こ 2024-11-03 08:03:43

这里的问题在于 Method.invoke 采用的变量参数(Object...)。

将此行更改

 s.invoke(this, ex);

为这样

 s.invoke(this, (Object)ex);

就可以了。

在后台,Object... 作为 Object[] 传递。 Java 看到您的 Object[] 并选择不将其包装在另一个 Object[] 中。通过转换为 Object,它现在只看到这一点并恢复到其正常的包装行为 - 与其他答案手动执行的操作相同。

The problem here is with the variable arguments (the Object...) that Method.invoke takes.

Changing this line

 s.invoke(this, ex);

to this

 s.invoke(this, (Object)ex);

will work.

In the background, Object... is passed as an Object[]. Java's seeing your Object[] and choosing not to wrap it up in another Object[]. By casting to Object, it now just sees that and reverts to its normal wrap-it-up behaviour - the same as what other answers are doing manually.

你与昨日 2024-11-03 08:03:43

您可以使用 dp4j 命令行来回答您的问题:

    $ javac -cp ../dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar -All -Averbose=true MyClass.java
MyClass.java:7: Note: 
public class MyClass {

public MyClass() {
    super();
}

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

@com.dp4j.Reflect()
public void invokeMyMethod() throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.IllegalArgumentException {
    final java.lang.reflect.Method myMethodWithArrayMethod = Class.forName("MyClass").getDeclaredMethod("myMethod", .java.lang.Object[].class);
    myMethodWithArrayMethod.setAccessible(true);
    myMethodWithArrayMethod.invoke(this, new .java.lang.Object[1][]{new .java.lang.Object[2][]{"hi", "there"}});
}

public static void main(String... args) throws Exception {
    new MyClass().invokeMyMethod();
}
}
public void invokeMyMethod() {
            ^

$ java MyClass
this is myMethod

You can use dp4j command-line to answer your question:

    $ javac -cp ../dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar -All -Averbose=true MyClass.java
MyClass.java:7: Note: 
public class MyClass {

public MyClass() {
    super();
}

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

@com.dp4j.Reflect()
public void invokeMyMethod() throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.IllegalArgumentException {
    final java.lang.reflect.Method myMethodWithArrayMethod = Class.forName("MyClass").getDeclaredMethod("myMethod", .java.lang.Object[].class);
    myMethodWithArrayMethod.setAccessible(true);
    myMethodWithArrayMethod.invoke(this, new .java.lang.Object[1][]{new .java.lang.Object[2][]{"hi", "there"}});
}

public static void main(String... args) throws Exception {
    new MyClass().invokeMyMethod();
}
}
public void invokeMyMethod() {
            ^

$ java MyClass
this is myMethod
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文