在Java反射的情况下,如何将参数作为反射类的vararg传递给调用方法?

e7arh2l6  于 2023-05-12  发布在  Java
关注(0)|答案(3)|浏览(133)

我有一个项目,我正在使用第三方库。但是,只有当用户在项目中复制了这些jar文件,或者使用现有的jar文件时,我才需要从第三方调用方法。为此,我使用反射来创建类并调用第三方库中的方法
库中的一个方法需要来自同一个库的另一个类的varargs作为参数。由于这两个类都是在我的主类中使用反射创建的,并且它们对应的方法也是使用反射创建的,我们如何将参数作为类的vararg传递给methodname.**invoke()**方法?
参考前面的代码片段。
//------A类-----------------

package com.demoA;

Class A {
   public void methodA(B... b) {
      // Contents of methodA...
   }
}

//------B类-----------------

package com.demoB;

Class B {
    // contents of class B here...
}

//-------类MainClass--------------

package com.mainclass;

Class MainClass {
    public static void main(String[] args) {
        Class<?> azz = Class.forName("com.demoA.A");
        Object aObject = azz.getDeclaredConstructor().newInstance();
        Method methodAReflected = null;
    
        for (Method m : azz.getMethods) {
            if (m.getName.equals("methodA")) {
                methodAReflected = m;
            }
        }
        
          Class bzz = Class.forName("com.demoB.B");
          Object bObject = bzz.getDeclaredConstructor().newInstance();
        
          methodAReflected.invoke(aObject, <how to pass varargs here>);
          // Passing only bObject or new Object[] { bObject } result in an IllegalArgumentException : type mismatch
    
    }
}

另外,当期望的参数是vararg时,是否有更好的方法(而不是遍历方法名)使用Java反射的**getMethod()**方法来创建反射的方法?

mqkwyuun

mqkwyuun1#

使用Array.newInstance创建一个新数组,并使用Array.set设置其元素。

Object methodAVarargs = Array.newInstance(bzz, 1);
Array.set(methodAVarargs, 0, bObject);
methodAReflected.invoke(aObject, methodAVarargs);

要用更短的代码找到方法,可以使用get(Declared)Method并传递bzzarrayType

Method methodAReflected = azz.getDeclaredMethod("methodA", bzz.arrayType());
lsmepo6l

lsmepo6l2#

你可以试着用这样的方法调用它:

B[] bObjectArray = <array of Bs>;
methodAReflected.invoke(aObject, (Object) bObjectArray);

你也可以查看官方的tutorial from Oracle,在 Invoking Methods with a Variable Number of Arguments 一节中,你可以找到使用你需要的类似方法的例子。

oipij1gg

oipij1gg3#

首先,我添加了一些调试代码来查看真实的的调用:

// add identificator to the class
class B {
    private final String id;

    public B(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}

// print args on invocation
class A {
    public void methodA(B... b) {
        var s = Arrays.stream(b).map(B::getId).reduce("", (acc, x) -> acc + x + ",");
        System.out.println("params (" + b.length + "): " + s);
    }
}

最后的代码:

public static void main(String[] args) {
        B bObject1 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b0");
        B bObject2 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b1");

        System.out.println("invoking with no args");
        methodAReflected.invoke(aObject, (Object) new B[]{});

        System.out.println("invoking with bObject1");
        methodAReflected.invoke(aObject, (Object) new B[]{bObject1});

        System.out.println("invoking with bObject1 and bObject2");
        methodAReflected.invoke(aObject, (Object) new B[]{bObject1, bObject2});
}

输出:

invoking with no args
params (0): 
invoking with bObject1
params (1): b0,
invoking with bObject1 and bObject2
params (2): b0,b1,

很简单。我们需要记住的是,我们将args作为raw Object传递。
首先,方法 * 总是 * 接受一个参数:
methodAReflected.getParameterCount() -> 1
让我们看看参数:

methodAReflected.getParameters() -> com.example.springsandbox.vararg.B... b
methodAReflected.getParameters()[0].executable -> public void com.example.springsandbox.vararg.A.methodA(com.example.springsandbox.vararg.B[])

相关问题