How do I invoke a Java method when given the method name as a string?

前端 未结 21 2161
耶瑟儿~
耶瑟儿~ 2020-11-21 04:50

If I have two variables:

Object obj;
String methodName = \"getName\";

Without knowing the class of obj, how can I call the met

相关标签:
21条回答
  • 2020-11-21 05:22

    For those who want a straight-forward code example in Java 7:

    Dog class:

    package com.mypackage.bean;
    
    public class Dog {
        private String name;
        private int age;
    
        public Dog() {
            // empty constructor
        }
    
        public Dog(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public void printDog(String name, int age) {
            System.out.println(name + " is " + age + " year(s) old.");
        }
    }
    

    ReflectionDemo class:

    package com.mypackage.demo;
    
    import java.lang.reflect.*;
    
    public class ReflectionDemo {
    
        public static void main(String[] args) throws Exception {
            String dogClassName = "com.mypackage.bean.Dog";
            Class<?> dogClass = Class.forName(dogClassName); // convert string classname to class
            Object dog = dogClass.newInstance(); // invoke empty constructor
    
            String methodName = "";
    
            // with single parameter, return void
            methodName = "setName";
            Method setNameMethod = dog.getClass().getMethod(methodName, String.class);
            setNameMethod.invoke(dog, "Mishka"); // pass arg
    
            // without parameters, return string
            methodName = "getName";
            Method getNameMethod = dog.getClass().getMethod(methodName);
            String name = (String) getNameMethod.invoke(dog); // explicit cast
    
            // with multiple parameters
            methodName = "printDog";
            Class<?>[] paramTypes = {String.class, int.class};
            Method printDogMethod = dog.getClass().getMethod(methodName, paramTypes);
            printDogMethod.invoke(dog, name, 3); // pass args
        }
    }
    

    Output: Mishka is 3 year(s) old.


    You can invoke the constructor with parameters this way:

    Constructor<?> dogConstructor = dogClass.getConstructor(String.class, int.class);
    Object dog = dogConstructor.newInstance("Hachiko", 10);
    

    Alternatively, you can remove

    String dogClassName = "com.mypackage.bean.Dog";
    Class<?> dogClass = Class.forName(dogClassName);
    Object dog = dogClass.newInstance();
    

    and do

    Dog dog = new Dog();
    
    Method method = Dog.class.getMethod(methodName, ...);
    method.invoke(dog, ...);
    

    Suggested reading: Creating New Class Instances

    0 讨论(0)
  • 2020-11-21 05:23

    If you do the call several times you can use the new method handles introduced in Java 7. Here we go for your method returning a String:

    Object obj = new Point( 100, 200 );
    String methodName = "toString";  
    Class<String> resultType = String.class;
    
    MethodType mt = MethodType.methodType( resultType );
    MethodHandle methodHandle = MethodHandles.lookup().findVirtual( obj.getClass(), methodName, mt );
    String result = resultType.cast( methodHandle.invoke( obj ) );
    
    System.out.println( result );  // java.awt.Point[x=100,y=200]
    
    0 讨论(0)
  • 2020-11-21 05:23

    using import java.lang.reflect.*;

    public static Object launchProcess(String className, String methodName, Class<?>[] argsTypes, Object[] methodArgs)
            throws Exception {
    
        Class<?> processClass = Class.forName(className); // convert string classname to class
        Object process = processClass.newInstance(); // invoke empty constructor
    
        Method aMethod = process.getClass().getMethod(methodName,argsTypes);
        Object res = aMethod.invoke(process, methodArgs); // pass arg
        return(res);
    }
    

    and here is how you use it:

    String className = "com.example.helloworld";
    String methodName = "print";
    Class<?>[] argsTypes = {String.class,  String.class};
    Object[] methArgs = { "hello", "world" };   
    launchProcess(className, methodName, argsTypes, methArgs);
    
    0 讨论(0)
  • 2020-11-21 05:24

    To complete my colleague's answers, You might want to pay close attention to:

    • static or instance calls (in one case, you do not need an instance of the class, in the other, you might need to rely on an existing default constructor that may or may not be there)
    • public or non-public method call (for the latter,you need to call setAccessible on the method within an doPrivileged block, other findbugs won't be happy)
    • encapsulating into one more manageable applicative exception if you want to throw back the numerous java system exceptions (hence the CCException in the code below)

    Here is an old java1.4 code which takes into account those points:

    /**
     * Allow for instance call, avoiding certain class circular dependencies. <br />
     * Calls even private method if java Security allows it.
     * @param aninstance instance on which method is invoked (if null, static call)
     * @param classname name of the class containing the method 
     * (can be null - ignored, actually - if instance if provided, must be provided if static call)
     * @param amethodname name of the method to invoke
     * @param parameterTypes array of Classes
     * @param parameters array of Object
     * @return resulting Object
     * @throws CCException if any problem
     */
    public static Object reflectionCall(final Object aninstance, final String classname, final String amethodname, final Class[] parameterTypes, final Object[] parameters) throws CCException
    {
        Object res;// = null;
        try {
            Class aclass;// = null;
            if(aninstance == null)
            {
                aclass = Class.forName(classname);
            }
            else
            {
                aclass = aninstance.getClass();
            }
            //Class[] parameterTypes = new Class[]{String[].class};
        final Method amethod = aclass.getDeclaredMethod(amethodname, parameterTypes);
            AccessController.doPrivileged(new PrivilegedAction() {
        public Object run() {
                    amethod.setAccessible(true);
                    return null; // nothing to return
                }
            });
            res = amethod.invoke(aninstance, parameters);
        } catch (final ClassNotFoundException e) {
            throw new CCException.Error(PROBLEM_TO_ACCESS+classname+CLASS, e);
        } catch (final SecurityException e) {
            throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_SECURITY_ISSUE, e);
        } catch (final NoSuchMethodException e) {
            throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_NOT_FOUND, e);
        } catch (final IllegalArgumentException e) {
            throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ILLEGAL_ARGUMENTS+String.valueOf(parameters)+GenericConstants.CLOSING_ROUND_BRACKET, e);
        } catch (final IllegalAccessException e) {
            throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ACCESS_RESTRICTION, e);
        } catch (final InvocationTargetException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_INVOCATION_ISSUE, e);
        } 
        return res;
    }
    
    0 讨论(0)
  • 2020-11-21 05:25

    With jooR it's merely:

    on(obj).call(methodName /*params*/).get()
    

    Here is a more elaborate example:

    public class TestClass {
    
        public int add(int a, int b) { return a + b; }
        private int mul(int a, int b) { return a * b; }
        static int sub(int a, int b) { return a - b; }
    
    }
    
    import static org.joor.Reflect.*;
    
    public class JoorTest {
    
        public static void main(String[] args) {
            int add = on(new TestClass()).call("add", 1, 2).get(); // public
            int mul = on(new TestClass()).call("mul", 3, 4).get(); // private
            int sub = on(TestClass.class).call("sub", 6, 5).get(); // static
            System.out.println(add + ", " + mul + ", " + sub);
        }
    }
    

    This prints:

    3, 12, 1

    0 讨论(0)
  • 2020-11-21 05:26
    Object obj;
    
    Method method = obj.getClass().getMethod("methodName", null);
    
    method.invoke(obj, null);
    
    0 讨论(0)
提交回复
热议问题