如何在java反射中将多个参数传递给一个方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16207283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 05:47:17  来源:igfitidea点击:

how to pass multiple parameters to a method in java reflections

javadynamicreflectionparameter-passing

提问by Mrunal Gosar

Hi i am using reflections to achieve something. I have been given class name, method name of that class and parameter values that needs to be passed to that method in a file(Take any file. Not a constraint). I have to call that method with the parameters. This methods do not return anything. There is a huge list of methods in this classes and parameter list of each varies.

嗨,我正在使用反射来实现某些目标。我已经获得了类名、该类的方法名以及需要在文件中传递给该方法的参数值(取任何文件。不是约束)。我必须使用参数调用该方法。此方法不返回任何内容。此类中有大量方法列表,每个方法的参数列表各不相同。

E.g: method1(String, String, int, boolean)method1(String, int, boolean)and likewise i have different permutations and combinations. So how can i achieve this. I have tried hard coding things with different switch clauses but it is a real overhead and risky thing to maintain. Can we dynamically do this thing, like on the fly read the method name and its parameter from the file and call it. Any small code snippet will be helpful. TIA.

例如:method1(String, String, int, boolean)method1(String, int, boolean)同样,我有不同的排列和组合。那么我怎样才能做到这一点。我曾尝试使用不同的 switch 子句对事物进行硬编码,但这是一个真正的开销和维护的风险。我们可以动态地做这个事情,比如从文件中动态读取方法名称及其参数并调用它。任何小的代码片段都会有所帮助。TIA。

采纳答案by Mrunal Gosar

Hi all i have found the solution to the above question. below is the sample code snippet.

大家好,我已经找到了上述问题的解决方案。下面是示例代码片段。

package reflections;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {
    public void method1(String str, int number) {
        System.out.println(str + number);
    }

    public void method1(String str) {
        System.out.println(str);
    }

    public void method1() {
        System.out.println("helloworld");
    }

    public static void main(String[] args) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException,
            NoSuchMethodException, SecurityException, IllegalArgumentException,
            InvocationTargetException {
        // Step 1) Make an object array and store the parameters that you wish
        // to pass it.
        Object[] obj = {};// for method1()
        // Object[] obj={"hello"}; for method1(String str)
        // Object[] obj={"hello",1}; for method1(String str,int number)
        // Step 2) Create a class array which will hold the signature of the
        // method being called.
        Class<?> params[] = new Class[obj.length];
        for (int i = 0; i < obj.length; i++) {
            if (obj[i] instanceof Integer) {
                params[i] = Integer.TYPE;
            } else if (obj[i] instanceof String) {
                params[i] = String.class;
            }
            // you can do additional checks for other data types if you want.
        }

        String methoName = "method1"; // methodname to be invoked
        String className = "reflections.ReflectionTest";// Class name
        Class<?> cls = Class.forName(className);
        Object _instance = cls.newInstance();
        Method myMethod = cls.getDeclaredMethod(methoName, params);
        myMethod.invoke(_instance, obj);
    }
}

I hope this will help others too.

我希望这也能帮助其他人。

回答by Devolus

public class ReflectionSample
{
    private Object mString = null;
    private int mValue;

    public ReflectionSample()
    {
    }

    public ReflectionSample(int oValue)
    {
        mValue = oValue;
    }

    public ReflectionSample(String oString)
    {
        mString = oString;
    }

    public ReflectionSample(String oString, int oValue)
    {
        setValues(oString, oValue);
    }

    public void setValues(String oString, int oValue)
    {
        mString = oString;
        mValue = oValue;
    }

    public String toString()
    {
        return ""+mString+":"+mValue;
    }

    public void run()
    {
        String oInput = "Teststring";
        Class<?> cls;
        String clsname = "main.ReflectionSample";
        Object rs = null;   // ReflectionSample
        Object rsc = null;

        System.out.println(this.getClass().getName());
        try
        {
            System.out.println(clsname);
            cls = Class.forName(clsname);
            if(cls == null)
            {
                System.err.println(clsname + " doesn't exist");
                return;
            }

            // Look for a constructor which has a single string
            Constructor<?> ct = null;
            Class<?>[] param_types = new Class<?>[1];
            Object[] arguments = new Object[1];

            param_types[0] = String.class;

            // get the string constructor
            ct = cls.getConstructor(param_types);

            // We only have one object
            arguments = new Object[1];
            arguments[0] = oInput;

            // Instantiate the object with passed in argument.
            rs = ct.newInstance(arguments);
            System.out.println("String constructor sample: "+rs);

            // Instantiate with default constructor
            param_types = new Class<?>[0];
            arguments = new Object[0];
            ct = cls.getConstructor(param_types);
            rs = ct.newInstance(arguments);
            rsc = rs; // Keep it for later, to lazy to call it again
            System.out.println("Default constructor sample: "+rs);

            // Instantiate with string and int constructor
            param_types = new Class<?>[2];
            arguments = new Object[2];

            // Must be in the same order as the params I think
            param_types[0] = String.class;
            param_types[1] = Integer.TYPE;      // <-- Its a primitive so use TYPE not Class

            arguments[0] = oInput;
            arguments[1] = new Integer(1);

            ct = cls.getConstructor(param_types);
            rs = ct.newInstance(arguments);
            System.out.println("String plus int constructor sample: "+rs);

            // call the setValues method
            param_types[0] = String.class;
            param_types[1] = Integer.TYPE;      // <-- Its a primitive so use TYPE not Class

            arguments[0] = oInput;
            arguments[1] = 1;

            System.out.println("setValues invocation before: "+rsc);
            Method m = cls.getMethod("setValues", param_types);
            m.invoke(rsc, arguments);
            System.out.println("setValues invocation after: "+rsc);

            // An alternative method to pass the parameters
            m = cls.getMethod("setValues", String.class, Integer.TYPE);
            m.invoke(rsc, oInput+"x", 2);
            System.out.println("setValues invocation after: "+rsc);
        }
        catch(Throwable e)
        {
            System.err.println(e.getLocalizedMessage());
        }
    }
}

Output:

输出:

main.ReflectionSample
main.ReflectionSample
String constructor sample: Teststring:0
Default constructor sample: null:0
String plus int constructor sample: Teststring:1
setValues invocation before: null:0
setValues invocation after: Teststring:1

Hope this helps.

希望这可以帮助。

I don't know if this is a newer feature in Java, but I have seen that you can use invoke now with parameters as well, instead of using an array, which might make your code better to read (This is the alternative way). If you need a variable number of arguments and you don't know beforehand how many there will be, allocating the array is defeinitly working and should also be backwardcompatible.

我不知道这是否是 Java 中较新的功能,但我已经看到您现在也可以使用带参数的 invoke,而不是使用数组,这可能会使您的代码更易于阅读(这是另一种方式) . 如果您需要可变数量的参数并且您事先不知道会有多少个,那么分配数组肯定是有效的,并且也应该是向后兼容的。

回答by Charindu Edirisooriya

A simple solution would be to create a Classwith the Arguments required to be passed:

一个简单的解决方案是Class使用需要传递的参数创建一个:

public class ObjectArguments {
  private PrintWriter out;
  private String productId;
  private int action;

  public ObjectArguments(PrintWriter out, String productId, int action) {
    this.out = out;
    this.productId = productId;
    this.action = action;
  }

  public PrintWriter getOut() {
    return out;
  }

  public String getProductId() {
    return productId;
  }

  public int getAction() {
    return action;
  }
}

Assuming that you want to invoke a class Foowith a method named bar.
Then it would be done like this.

假设您想Foo使用名为 的方法调用一个类bar
然后它会像这样完成。

PrintWriter out = null;
String productId = null;
int action = 0;

Class[] paramArguments = new Class[1];  
paramArguments[0] = ObjectArguments.class;  

ObjectArguments newObj = new ObjectArguments(out,productId,action);

Class cls = Class.forName("Foo");
Object obj = cls.newInstance();

Method method = cls.getDeclaredMethod("bar", paramArguments);
method.invoke(obj, newObj);