【问题标题】:How to work with varargs and reflection如何使用可变参数和反射
【发布时间】:2011-02-05 17:59:23
【问题描述】:

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

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)

【问题讨论】:

    标签: java reflection variadic-functions


    【解决方案1】:
    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});
    

    【讨论】:

    • 谢谢!但现在我被困在了调用上。
    • @PeterMmm 好。顺便说一句,对有用的(包括已接受的)答案进行投票是一种公认​​的做法。您只有 2 个赞成票,这与 SO 的想法相反。
    • 你也可以m.invoke(this, (Object) a);(看我的解决方案)。
    • @Bozho,我的情况是: void foo() 函数有参数 Param... param(提示:Param 是泛型类型)而不是 String... s。我使用了 new Object[] {new URL("google.com")},但得到以下错误:IllegalArgumentException: argument 1 should have type java.lang.Object[], got java.net.URL
    【解决方案2】:

    //编辑前:

    您的问题是getMethod 寻找public 成员。

    来自Class.getMethod(强调我的):

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

    所以你有两个选择:

    • 制作public void foo(String... s)并使用getMethod
    • 改用getDeclaredMethod

    请注意,getField/sgetDeclaredField/sgetConstructor/sgetDeclaredConstructor/s 存在相同的差异。


    //invoke问题

    这特别讨厌,但是如果您需要将引用类型的数组作为唯一参数传递,invoke(Object obj, Object... args) 会变得很棘手,因为它可以转换为 Object[],即使它应该是而是包裹在 new Object[1] 中。

    你可以这样做:

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

    这绕过了可变参数机制。更简洁,你也可以这样做:

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

    转换为Object 使可变参数机制为您完成创建数组的工作。

    null 作为参数传递给可变参数时也需要这个技巧,并且与反射无关。

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

    【讨论】:

    • @polygenelubricants,我的情况是:void foo() 函数有参数 Param... param(提示:Param 是泛型类型)而不是 String... s。我使用了 new Object[] {new URL("google.com")},但出现以下错误:IllegalArgumentException: argument 1 should have type java.lang.Object[], got java.net.URL.提前谢谢你。
    猜你喜欢
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 2011-12-18
    • 1970-01-01
    • 2011-01-13
    相关资源
    最近更新 更多