667 votes

Comment puis-je invoquer une méthode en Java quand donné le nom de la méthode comme une chaîne de caractères?

Si j'ai deux variables:

Object obj;
String methodName = "getName";

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

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

957voto

Henrik Paul Points 22787

Le 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 d'identifier très spécifiques de la méthode dont vous avez besoin (si il y a plusieurs surchargé disponibles, si la méthode n'a pas d'arguments, mais seulement donner 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, de laisser de côté les arguments .invoquer, si vous n'en avez pas. Mais ouais. Lisez à propos de Java Réflexion

188voto

Owen Points 1030

Utiliser la réflexion:

http://java.sun.com/docs/books/tutorial/reflect/member/methodInvocation.html

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

Où:

"le nom de classe" est le nom de la classe

objectToInvokeOn est de type Objet et l'objet que vous voulez appeler la méthode sur "la méthode nom" est le nom de la méthode que vous souhaitez appeler

parameterTypes est de type Class [] et decalres les paramètres de la méthode prend

params est de type Object [] et déclare les paramètres passés à la méthode

55voto

Petr Macek Points 615

La méthode peut être appelée comme ça. Il y a également plus de possibilités (vérifier l'api reflection), 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);
    }



}

16voto

Tout d'abord, ne l'est pas. Éviter ce genre de code. Il a tendance à être vraiment mauvais code et l'insécurité (voir la section 6 de Codage Sécurisé des lignes Directrices pour la Le Langage de Programmation Java, la version 2.0).

Si vous devez le faire, préférez java.les haricots à la réflexion. Haricots roulés de réflexion permettant relativement sûr et conventionnelles d'accès.

14voto

VonC Points 414372

Pour compléter mon collègue réponses, Vous voulez faire attention:

  • statique ou de l'instance d'appel (dans un cas, vous n'avez pas besoin d'une instance de la classe, dans l'autre, vous pourriez avoir besoin de s'appuyer sur un existant constructeur par défaut qui peuvent ou peuvent ne pas y être)
  • public ou non public de l'appel de méthode (pour cette dernière,vous devez appeler setAccessible sur la méthode dans une doPrivileged bloc, d'autres findbugs de ne pas être heureux)
  • l'encapsulation dans un plus gérable applicative exception si vous voulez relancer les nombreux système java exceptions (d'où le CCException dans le code ci-dessous)

Voici une vieille java1.4 code qui prend en compte de 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;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X