Comment puis-je appeler une méthode Java lorsque le nom de la méthode est donné en tant que chaîne?

Si j'ai deux variables:

Object obj;
String methodName = "getName";

Sans connaître la classe de obj, comment puis-je appeler la méthode identifiés par methodName sur elle?

La méthode appelée n'a pas de paramètres, et une valeur de retour String. C'est un getter pour un bean Java.

585
demandé sur Joachim Sauer 2008-10-02 09:15:43

18 réponses

Codage de la hanche, ce serait quelque chose comme:

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

Les paramètres identifient la méthode très spécifique dont vous avez besoin (s'il y en a plusieurs surchargés, si la méthode n'a pas d'arguments, donnez seulement methodName).

Ensuite, vous appelez cette méthode en appelant

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

Encore une fois, omettez les arguments dans .invoke, Si vous n'en avez pas. Mais ouais. Lisez à propos de Réflexion Java

849
répondu Henrik Paul 2016-09-29 14:13:34

Utilisez l'invocation de la méthode à partir de la réflexion:

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

Où:

  • "class name" est le nom de la classe
  • objectToInvokeOn est de type Objet et l'objet que vous voulez appeler la méthode sur
  • "method name" est le nom de la méthode que vous voulez l'appeler
  • parameterTypes est de type Class[] et déclare les paramètres de la méthode prend
  • params est de type Object[] et déclare les paramètres passés à la méthode
161
répondu Owen 2018-04-20 17:42:48

Pour ceux qui veulent un exemple de code simple dans Java 7:

Dog classe:

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 classe:

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

Sortie: Mishka is 3 year(s) old.


Vous pouvez appeler le constructeur avec des paramètres de cette façon:

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

Vous pouvez également supprimer

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

Et faire

Dog dog = new Dog();

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

Bibliographie: création de nouvelles Instances de classe

67
répondu silver 2015-10-31 07:06:05

La méthode peut être invoquée comme ceci. Il y a aussi plus de possibilités (Vérifiez l'api de réflexion), mais c'est le plus simple:

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



}
51
répondu Petr Macek 2008-10-02 05:33:31

D'abord, ne le faites pas. évitez ce genre de code. Il a tendance à être vraiment mauvais code et non sécurisé aussi (voir la section 6 de Secure Coding Guidelines for the Langage de programmation Java, version 2.0 ).

Si vous devez le faire, préférez java.les haricots à la réflexion. Les haricots enveloppent la réflexion permettant un accès relativement sûr et conventionnel.

16
répondu Tom Hawtin - tackline 2015-02-13 19:26:23

Pour compléter les réponses de mon collègue, vous voudrez peut-être porter une attention particulière à:

  • appels statiques ou d'instance (dans un cas, vous n'avez pas besoin d'une instance de la classe, dans l'autre, vous devrez peut-être compter sur un constructeur par défaut existant qui peut ou non être là)
  • appel de méthode public ou non public (pour ce dernier, vous devez appeler setAccessible sur la méthode dans un bloc doPrivileged, other findbugs ne sera pas heureux)
  • encapsuler en une exception applicative plus gérable si vous voulez rejeter les nombreuses exceptions du système java (d'où L'Exception CCException dans le code ci-dessous)

Voici un ancien code java1. 4 qui prend en compte ces 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;
}
12
répondu VonC 2008-10-02 05:51:12
//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");
10
répondu anujin 2013-04-30 05:46:18
Object obj;

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

method.invoke(obj, null);
8
répondu chickeninabiscuit 2008-10-02 05:22:24

Cela ressemble à quelque chose qui est faisable avec le paquet Java Reflection.

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

En particulier sous invoquant des méthodes par nom:

Importer java.lang.refléter.*;

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);
     }
  }
}
6
répondu zxcv 2008-10-02 05:22:24

Si vous faites l'appel plusieurs fois, vous pouvez utiliser les nouveaux handles de méthode introduits dans Java 7. Nous y voilà pour votre méthode renvoyant une chaîne:

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]
6
répondu Christian Ullenboom 2017-02-28 22:02:59
Method method = someVariable.class.getMethod(SomeClass);
String status = (String) method.invoke(method);

SomeClass c'est la classe et someVariable est une variable.

4
répondu Subrahmanya Prasad 2018-04-20 17:44:05

Veuillez vous référer au code suivant peut vous aider.

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

Merci....

4
répondu Rahul Karankal 2018-04-24 12:37:58

Étudiant.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();
        }
     }
}
3
répondu user8387971 2018-04-20 17:43:08

Je fais ceci comme ceci:

try {
    YourClass yourClass = new YourClass();
    Method method = YourClass.class.getMethod("yourMethodName", ParameterOfThisMethod.class);
    method.invoke(yourClass, parameter);
} catch (Exception e) {
    e.printStackTrace();
}
3
répondu Marcel Jacques Machado 2018-04-20 17:44:22

Vous devez utiliser reflection-init un objet de classe, puis une méthode dans cette classe, puis appeler cette méthode sur un objet avec paramètres optionnels . N'oubliez pas d'envelopper l'extrait suivant dans try-catch block

J'espère que ça aide!

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);
1
répondu nurxyz 2015-07-09 14:51:37

Cela fonctionne bien pour moi :

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

}

Sortie:

My input testparam

Je suis capable d'invoquer la méthode en passant son nom à une autre méthode (comme main).

1
répondu Laxman G 2016-08-10 13:40:15

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

Et voici comment vous l'utilisez:

String className = "com.example.helloworld";
String methodName = "print";
Class<?>[] argsTypes = {String.class,  String.class};
Object[] methArgs = { "hello", "world" };   
launchProcess(className, methodName, argsTypes, methArgs);
1
répondu dina 2016-11-23 07:32:23

Pour moi, un moyen assez simple et infaillible serait de simplement faire une méthode d'appel de méthode comme ceci:

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

Ensuite, lorsque vous devez appeler la méthode, mettez simplement quelque chose comme ceci

//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()); 
-9
répondu SMayne 2014-04-18 15:11:11