2012-02-27 96 views
1

我想了解使用Java反射调用变量方法可能会发生什么。比方说,我们有一个简单的方法:用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的各种色调。

我很清楚这里有什么东西。我的猜测是,这与变量如何编入可变参数值有关。我发现了this four year old blog post which seems to be talking about the same issue,但我无法重现那里的'成功'案例。有关可能会发生什么的任何想法?

回答

8

需要在Object[][]通过在这种情况下:

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

的原因在于,所述单个things参数是由编译器变换为Object[]类型的单个参数,并且invoke带有一个数组与参数值。

考虑更多的参数的方法,以使其更清晰:

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

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

invoke本身声明为可变参数,这样就可以让编译器为您创建的外部阵列。但是如果你通过Object[],它不会这样做,因为它认为你已经这样做了。因此,只要隐藏编译器的事实:

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

注意投在第一线,现在则编译器不会再现在已经有一个数组,因此它创建一个。在第二行中,这是不需要的,因为编译器无论如何都没有其他机会。

编辑: 请注意,你的代码甚至不编译,因为你错过了传递类的实例与doAllTheThings方法invoke(我把它命名为o在我的代码)。

+0

非常感谢回复,特别是对编辑。 (您在编辑中遇到的疏忽解释了为什么我无法获得示例代码来工作!) – 2012-02-27 20:07:59