Как вызвать метод Java, если имя метода указано в виде строки?

Если у меня есть две переменные:

Object obj;
String methodName = "getName";

Не зная класса objкак я могу вызвать метод, определенный methodName в теме?

Вызываемый метод не имеет параметров, и String возвращаемое значение Это геттер для Java-бина.

23 ответа

Решение

Кодирование от бедра, это было бы что-то вроде:

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) { ... }
  catch (NoSuchMethodException e) { ... }

Параметры определяют очень специфический метод, который вам нужен (если доступно несколько перегруженных версий, если метод не имеет аргументов, выдают только methodName).

Затем вы вызываете этот метод, вызывая

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) { ... }
  catch (IllegalAccessException e) { ... }
  catch (InvocationTargetException e) { ... }

Опять же, опустить аргументы в .invokeесли у вас их нет. Но да. Читайте о Java Reflection

Используйте вызов метода из отражения:

Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod("method name", parameterTypes);
method.invoke(objectToInvokeOn, params);

Куда:

  • "class name" это название класса
  • objectToInvokeOn имеет тип Object и является объектом, для которого вы хотите вызвать метод
  • "method name" это имя метода, который вы хотите вызвать
  • parameterTypes имеет тип Class[] и объявляет параметры, которые принимает метод
  • params имеет тип Object[] и объявляет параметры, которые будут переданы методу

Для тех, кто хочет простой пример кода в Java 7:

Dogучебный класс:

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учебный класс:

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

Выход:Mishka is 3 year(s) old.


Вы можете вызвать конструктор с параметрами следующим образом:

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

Кроме того, вы можете удалить

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

и делать

Dog dog = new Dog();

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

Рекомендуемое чтение: создание новых экземпляров классов

Метод может быть вызван следующим образом. Есть также больше возможностей (проверьте API отражения), но это самый простой:

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

import org.junit.Assert;
import org.junit.Test;

public class ReflectionTest {

    private String methodName = "length";
    private String valueObject = "Some object";

    @Test
    public void testGetMethod() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Method m = valueObject.getClass().getMethod(methodName, new Class[] {});
        Object ret = m.invoke(valueObject, new Object[] {});
        Assert.assertEquals(11, ret);
    }



}

Во-первых, не надо. Избегайте такого рода кода. Это, как правило, очень плохой код и небезопасный (см. Раздел 6 Руководства по безопасному кодированию для языка программирования Java, версия 2.0).

Если вы должны это сделать, предпочтите java.beans рефлексии. Отражение в бобах обеспечивает относительно безопасный и обычный доступ.

Чтобы завершить ответы моего коллеги, вы можете обратить пристальное внимание на:

  • статические вызовы или вызовы экземпляра (в одном случае вам не нужен экземпляр класса, в другом - вам может потребоваться существующий конструктор по умолчанию, который может быть или не быть)
  • открытый или непубличный вызов метода (для последнегонеобходимо вызвать setAccessible для метода в блоке doPrivileged, другие findbugs не будут удовлетворены)
  • инкапсуляция в еще одно управляемое аппликативное исключение, если вы хотите отбросить многочисленные системные исключения java (отсюда CCException в приведенном ниже коде)

Вот старый код java1.4, который учитывает эти моменты:

/**
 * 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;
}

Индексирование (быстрее)

Вы можете использовать FunctionalInterfaceдля сохранения методов в контейнере для их индексации. Вы можете использовать контейнер массива, чтобы вызывать их по числам или хэш-карту, чтобы вызывать их по строкам. С помощью этой уловки вы можете индексировать свои методы, чтобы вызывать их динамически быстрее.

@FunctionalInterface
public interface Method {
    double execute(int number);
}

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        this::square,
        this::circle
    };

    private double square(int number) {
        return number * number;
    }

    private double circle(int number) {
        return PI * number * number;
    }

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(number);
    }
}

Лямбда-синтаксис

Вы также можете использовать лямбда-синтаксис:

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        number -> {
            return number * number;
        },
        number -> {
            return PI * number * number;
        },
    };

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(number);
    }
}
Object obj;

Method method = obj.getClass().getMethod("methodName", null);

method.invoke(obj, null);
//Step1 - Using string funClass to convert to class
String funClass = "package.myclass";
Class c = Class.forName(funClass);

//Step2 - instantiate an object of the class abov
Object o = c.newInstance();
//Prepare array of the arguments that your function accepts, lets say only one string here
Class[] paramTypes = new Class[1];
paramTypes[0]=String.class;
String methodName = "mymethod";
//Instantiate an object of type method that returns you method name
 Method m = c.getDeclaredMethod(methodName, paramTypes);
//invoke method with actual params
m.invoke(o, "testparam");

Если вы делаете вызов несколько раз, вы можете использовать новые дескрипторы метода, представленные в Java 7. Здесь мы рассмотрим ваш метод, возвращающий строку:

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]

Я делаю это так:

try {
    YourClass yourClass = new YourClass();
    Method method = YourClass.class.getMethod("yourMethodName", ParameterOfThisMethod.class);
    method.invoke(yourClass, parameter);
} catch (Exception e) {
    e.printStackTrace();
}

Это звучит как что-то выполнимое с пакетом Java Reflection.

http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html

Особенно в разделе Методы вызова по имени:

импорт java.lang.reflect.*;

public class method2 {
  public int add(int a, int b)
  {
     return a + b;
  }

  public static void main(String args[])
  {
     try {
       Class cls = Class.forName("method2");
       Class partypes[] = new Class[2];
        partypes[0] = Integer.TYPE;
        partypes[1] = Integer.TYPE;
        Method meth = cls.getMethod(
          "add", partypes);
        method2 methobj = new method2();
        Object arglist[] = new Object[2];
        arglist[0] = new Integer(37);
        arglist[1] = new Integer(47);
        Object retobj 
          = meth.invoke(methobj, arglist);
        Integer retval = (Integer)retobj;
        System.out.println(retval.intValue());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}

Вот ГОТОВЫ ИСПОЛЬЗОВАТЬ МЕТОДЫ:

Чтобы вызвать метод без аргументов:

public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    object.getClass().getDeclaredMethod(methodName).invoke(object);
}

Чтобы вызвать метод с аргументами:

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

Используйте вышеуказанные методы, как показано ниже:

package practice;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class MethodInvoke {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
        String methodName1 = "methodA";
        String methodName2 = "methodB";
        MethodInvoke object = new MethodInvoke();
        callMethodByName(object, methodName1);
        callMethodByName(object, methodName2, 1, "Test");
    }

    public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName).invoke(object);
    }

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

    void methodA() {
        System.out.println("Method A");
    }

    void methodB(int i, String s) {
        System.out.println("Method B: "+"\n\tParam1 - "+i+"\n\tParam 2 - "+s);
    }
}

Выход:

Способ А  
Метод Б:  
	Param1 - 1  
Парам 2 - Тест

Пожалуйста, обратитесь следующий код может помочь вам.

public static Method method[];
public static MethodClass obj;
public static String testMethod="A";

public static void main(String args[]) 
{
    obj=new MethodClass();
    method=obj.getClass().getMethods();
    try
    {
        for(int i=0;i<method.length;i++)
        {
            String name=method[i].getName();
            if(name==testMethod)
            {   
                method[i].invoke(name,"Test Parameters of A");
            }
        }
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

Спасибо....

Method method = someVariable.class.getMethod(SomeClass);
String status = (String) method.invoke(method);

SomeClass это класс и someVariable переменная

Student.java

class Student{
    int rollno;
    String name;

    void m1(int x,int y){
        System.out.println("add is" +(x+y));
    }

    private void m3(String name){
        this.name=name;
        System.out.println("danger yappa:"+name);
    }
    void m4(){
        System.out.println("This is m4");
    }
}

StudentTest.java

import java.lang.reflect.Method;
public class StudentTest{

     public static void main(String[] args){

        try{

            Class cls=Student.class;

            Student s=(Student)cls.newInstance();


            String x="kichha";
            Method mm3=cls.getDeclaredMethod("m3",String.class);
            mm3.setAccessible(true);
            mm3.invoke(s,x);

            Method mm1=cls.getDeclaredMethod("m1",int.class,int.class);
            mm1.invoke(s,10,20);

        }
        catch(Exception e){
            e.printStackTrace();
        }
     }
}

С jooR это просто:

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

Вот более подробный пример:

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

Это печатает:

3, 12, 1

С помощью 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);
}

и вот как вы это используете:

String className = "com.example.helloworld";
String methodName = "print";
Class<?>[] argsTypes = {String.class,  String.class};
Object[] methArgs = { "hello", "world" };   
launchProcess(className, methodName, argsTypes, methArgs);

Вы должны использовать отражение - инициализировать объект класса, затем метод в этом классе, а затем вызывать этот метод для объекта с необязательными параметрами. Не забудьте обернуть следующий фрагмент в блок try-catch

Надеюсь, поможет!

Class<?> aClass = Class.forName(FULLY_QUALIFIED_CLASS_NAME);
Method method = aClass.getMethod(methodName, YOUR_PARAM_1.class, YOUR_PARAM_2.class);
method.invoke(OBJECT_TO_RUN_METHOD_ON, YOUR_PARAM_1, YOUR_PARAM_2);

Это работает нормально для меня:

public class MethodInvokerClass {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException, InvocationTargetException, InstantiationException {
        Class c = Class.forName(MethodInvokerClass.class.getName());
        Object o = c.newInstance();
        Class[] paramTypes = new Class[1];
        paramTypes[0]=String.class;
        String methodName = "countWord";
         Method m = c.getDeclaredMethod(methodName, paramTypes);
         m.invoke(o, "testparam");
}
public void countWord(String input){
    System.out.println("My input "+input);
}

}

Выход:

My input testparam

Я могу вызвать метод, передав его имя другому методу (например, main).

Для тех, кто вызывает метод в том же классе из нестатического метода, см. Коды ниже:

      class Person {
    public void method1() {
        try {
            Method m2 = this.getClass().getDeclaredMethod("method2");
            m1.invoke(this);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public void method2() {
        // Do something
    }

}

Предположим, вы вызываете статический метод из статического метода в том же классе. Для этого вы можете использовать следующий код.

      class MainClass
{
  public static int test()
  {
    return 123;
  }

  public static void main(String[] args)
  {
    Method method = MainClass.class.getMethod("test");
    int answer = (int) method.invoke(null); // answer evaluates to 123
  }
}

Чтобы объяснить, поскольку мы не стремимся создавать здесь настоящее объектно-ориентированное программирование, а значит, избегая создания ненужных объектов, мы вместо этого будем использовать свойство ссылаться .

Тогда мы перейдем для метода, потому что у нас нет объекта для выполнения этой операции.

И, наконец, поскольку мы, программисты, знаем, что ожидаем целое число, мы явно приводим возвращаемое значение обращение к целому числу.

Теперь вы можете задаться вопросом: «В чем вообще смысл всего этого не объектно-ориентированного программирования на Java?» Вариант использования - решение проблем ProjectEuler на Java, и все, что вам нужно, - это один исходный файл Java, содержащий все решения, но вы хотите передать аргументы командной строки, чтобы определить, какую проблему ProjectEuler следует запустить. По крайней мере, это был мой вариант использования.

Для меня довольно простым и надежным способом было бы просто сделать метод вызывающего метода следующим образом:

public static object methodCaller(String methodName)
{
    if(methodName.equals("getName"))
        return className.getName();
}

тогда, когда вам нужно вызвать метод, просто поместите что-то вроде этого

//calling a toString method is unnessary here, but i use it to have my programs to both rigid and self-explanitory 
System.out.println(methodCaller(methodName).toString()); 
Другие вопросы по тегам