如何使用varargs和reflection

简单的问题,如何使这段代码工作?

public class T { public static void main(String[] args) throws Exception { new T().m(); } public // as mentioned by Bozho void foo(String... s) { System.err.println(s[0]); } void m() throws Exception { String[] a = new String[]{"hello", "kitty"}; System.err.println(a.getClass()); Method m = getClass().getMethod("foo", a.getClass()); m.invoke(this, (Object[]) a); } } 

输出:

 class [Ljava.lang.String; Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) 

 Test.class.getDeclaredMethod("foo", String[].class); 

作品。 问题是getMethod(..)只搜索public方法。 来自javadoc:

返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定公共成员方法。

更新:成功获取方法后,您可以使用以下方法调用它:

 m.invoke(this, new Object[] {new String[] {"a", "s", "d"}}); 

也就是说 – 创建一个带有一个元素的新Object数组 – String数组。 使用您的变量名称,它看起来像:

 m.invoke(this, new Object[] {a}); 

//编辑之前:

您的问题是getMethod查找public成员的事实。

Class.getMethod (强调我的):

返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定公共成员方法

所以你有两个选择:

  • make public void foo(String... s)并使用getMethod
  • 请改用getDeclaredMethod

请注意, getField/s vs getDeclaredField/sgetConstructor/s vs getDeclaredConstructor/s存在相同的差异。


// invoke问题

这特别令人讨厌,但是如果你需要传递一个引用类型数组作为唯一参数, invoke(Object obj, Object... args)会使它变得棘手,因为它可以转换为Object[] ,即使它应该被包装在一个new Object[1]

你可以做:

 m.invoke(this, new Object[] {a}); // Bohzo's solution 

这绕过了vararg机制。 你可以更简洁地做到:

 m.invoke(this, (Object) a); 

Object的强制转换使vararg机制能够为您创建数组。

null作为参数传递给varargs时也需要这个技巧,并且与reflection无关。

 public void foo(String... ss) { System.out.println(ss[0]); } foo(null); // causes NullPointerException foo((String) null); // prints "null"