Problem description
Class target. Java has an execute method, which 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
}
}
As a result, the console reports an error
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 like
method.invoke(object, arg1, arg2)
In such a representation, an array is implicitly created, similar to new object [] {arg1, arg2}, and then is used as the parameter of the invoke method. But if the parameter of the target method is an array, such as
method.invoke(object, Object[])
The compiler will think that you have put all the parameters in the array, so it won’t wrap them again. In this case, the elements in the array , not the array itself, are passed to the target method as parameters
So let’s look back and forth at the above example. In fact, the main method finally attempts to call the execute method with a string type as a parameter through reflection. 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 very simple, as long as package the array as the first element of the object array , then 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 using reflection to call a method, if the input parameter of the target method is an array, the array should be wrapped in another object array