Java反射調用報錯 java.lang.IllegalArgumentException: wrong number of arguments

問題描述

Target.java有一個execute()方法,用一個String數組做爲參數java

public class Target {
    public void execute(String[] args) {
        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
    }
}

結果控制檯出現報錯code

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)get

問題分析

找到Method.invoke方法,其實它接收的是一個變長參數(Varargs)編譯器

public Object invoke(Object obj, Object... args)it

當編譯器發現相似io

method.invoke(object, arg1, arg2)編譯

這樣的表示時,會隱式地建立一個數組,相似new Object [] {arg1, arg2},而後將該數組做爲invoke方法的參數。 可是若是目標方法的參數原本就是一個數組的時候,如class

method.invoke(object, Object[])thread

編譯器會認爲你已經將全部的參數放到數組裏面了,從而不會再次包裝。因而在這種狀況下,做爲參數傳遞給目標方法的,實際上是數組裏面的元素,而不是數組自己。

因此咱們來回看上面的例子,其實main方法最終經過反射嘗試調用的是,以一個String類型做爲參數的execute方法,咱們來作個試驗

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
    }
}

最終打印出來的是(注意兩個方法參數是不同的)

call execute method with parameter type String

問題解決

其實這種狀況的解決方法很簡單,只要把數組包裝成Object數組的第一個元素就行了,這樣編譯器就會把數組自己做爲參數,傳遞給目標方法了,以下:

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
    }
}

總結

當用反射調用方法時,若是目標方法的入參是一個數組,則要把數組包裝到另外一個Object數組中。

相關文章
相關標籤/搜索