Problem Description
The class Target.java has an execute() method that takes a String array as a parameter
public class Target { public void execute(String[] args) { System.out.println("call execute method with parameter type String[]"); } }
Call this method through reflection in the following way
public class Test { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { String[] parameters = {"1"}; // parameter array Class targetClass = Class.forName("Target");// get target class "Target" Object instance= targetClass.newInstance(); Method execute = targetClass.getDeclaredMethod("execute", String[].class);// get target method "execute" execute.invoke(instance, parameters);// invoke method } }
Error in result console
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:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at Test.main(Test.java:16)
problem analysis
Find the Method.invoke method, which actually receives a variable length parameter (Varargs).
public Object invoke(Object obj, Object... args)
When the compiler finds something similar
method.invoke(object, arg1, arg2)
When represented this way, an array is implicitly created, similar to the new Object [] {arg1, arg2}, and then used as an argument to the invoke method. But if the parameter of the target method is an array, such as
method.invoke(object, Object[])
The compiler will assume that you have put all the parameters in the array and will not wrap them again.In this case, what is passed as a parameter to the target method is actually the elements inside the array, not the array itself.
So let's look back and forth at the example above, in fact, the main method ultimately calls the execute method with a String type as a parameter through reflection, so let's do an experiment
public class Target { public void execute(String[] args) { System.out.println("call execute method with parameter type String[]"); } public void execute(String arg) { System.out.println("call execute method with parameter type String"); } } public class Test { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { String[] parameters = {"1"}; // parameter array Class targetClass = Class.forName("Target");// get target class "Target" Object instance= targetClass.newInstance(); Method execute = targetClass.getDeclaredMethod("execute", String.class);// get target method "execute" execute.invoke(instance, parameters);// invoke method } }
The final print is (note that the two method parameters are different)
call execute method with parameter type String
Problem solving
In fact, the solution to this situation is simple. Just wrap the array as the first element of the Object array, and the compiler will pass the array itself as a parameter to the target method, as follows:
public class Test { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { String[] parameters = {"1"}; // parameter array Class targetClass = Class.forName("Target");// get target class "Target" Object instance = targetClass.newInstance(); Method execute = targetClass.getDeclaredMethod("execute", String[].class);// get target method "execute" execute.invoke(instance, new Object[] {parameters});// invoke method } }
summary
When calling a method with reflection, wrap the array in another Object array if the target method's input is an array.