2010-11-09 12 views
19

Digamos que tengo Method1 (void), Method2 (void) ...cómo llamar a un método Java usando un nombre de variable?

¿Hay alguna manera de elegir uno con una variable?

String MyVar=2; 
MethodMyVar(); 
+3

Usted puede, pero ¿por qué quieres hacer esto? – jjnguy

+3

Me encontré con un caso por esta vez, donde usar reflection + a HashMap tiene más sentido que un masivo si/else de comparaciones de cadenas y llamadas a métodos condicionales. – cHao

+1

@cHao: seguramente un mejor esquema habría sido escribir una interfaz y usar un HashMap para almacenar objetos de esa interfaz como un análogo para funciones lambda. –

Respuesta

30

Uso reflexión:

Method method = WhateverYourClassIs.class.getDeclaredMethod("Method" + MyVar); 
method.invoke(); 
+1

+1, con la advertencia de que la reflexión puede ser lenta y el compilador ya no aplica la seguridad de tipo. – cHao

+0

WRT su ejemplo, ¿esto no buscaría 'Método2' como el método? – javamonkey79

+0

¿Qué dependencias tienen 'Método' y' Clase'? Estoy tratando de usar esto y me sale el error: 'método no estático getDeclaredMethod no se puede hacer referencia desde un contexto estático' – hellyale

6

podría utilizar el patrón de diseño Estrategia y un mapeo de la cadena que tiene al objeto estrategia concreta correspondiente. Este es el medio seguro y eficiente.

Por lo tanto, tiene un HashMap<String,SomeInterfaceYouWantToInvokeSuchAsRunnableWithPseudoClosures> búsqueda.

por ejemplo, algo a lo largo de las líneas de:

final static YourType reciever = this; 
HashMap<String,Runnable> m = new HashMap<String,Runnable> {{ 
    add("a", new Runnable() { 
     @Override public void run() { 
     reciever.a(); 
     } 
    }); 
    .... 
}}; 
// but check for range validity, etc. 
m.get("a").run() 

También se puede utilizar la reflexión o "invertir" el problema y utilizar el polimorfismo

+1

Corregí 'sobrescribir' a' @ Override' de Java, pero en realidad es innecesario. También las enumeraciones pueden ser útiles en algunos casos relacionados. La reflexión es, por supuesto, malvada. –

+0

Hice solo una pequeña cantidad de investigación antes de preguntar esto, pero ¿por qué la reflexión es mala? Me parece muy poderoso, y parece que podría hacer que escribir un código sea más fácil. Honestamente, lo que escribiste arriba es la cosa más genial que he visto en toda la semana. Sin embargo, tengo una pregunta: ¿es su método de utilizar un hashmap mejor que los ejemplos de reflexión en este mismo hilo? – michaelsnowden

+0

'add (" a ", ...' debe ser 'put (" a ", ...' –

9

Sólo a través de la reflexión. Consulte el paquete java.lang.reflect.

Usted podría intentar algo como:

Method m = obj.getClass().getMethod("methodName" + MyVar); 
m.invoke(obj); 

Su código puede ser diferente si el método tiene parámetros y hay todo tipo de gestión de excepciones que falta.

Pero pregúntese si esto es realmente necesario? Puede cambiar algo sobre su diseño para evitar esto. El código de reflexión es difícil de entender y es más lento que simplemente llamar al obj.someMethod().

Buena suerte. Feliz Codificación.

+0

¿Qué es 'obj'? – Alvaro

+0

' obj' es solo un nombre de variable que inventé, pero es cualquier objeto en el que desee invocar un método de forma reflexiva. – Todd

+0

¿Cómo pasar un parámetro a un método reflectante? – Salman

0

No estoy seguro de cómo funciona la respuesta aceptada para method.invoke() sin primer argumento de que el método estático es null (el valor ficticio aún funciona). Según The Java™ Tutorials:

El primer argumento es la instancia de objeto en que el presente método en particular es que se invoca. (Si el método es estático, el primer argumento debería ser nulo.)

La siguiente muestra una completos ejemplos (Main.java), tanto para estático (por clase) VS no estático (por ejemplo), además de ejemplo adicional para método con argumento, importación clase es necesario, captura excepción, y también método de la superclase ejemplo.

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

class Love { 
    protected void Method4() { 
     System.out.println("calls super protected method by instance"); 
    } 

    public void Method5() { 
     System.out.println("calls super public method by instance"); 
    } 
} 

class Main extends Love { 

    static void Method2(int y) { 
     System.out.println("by class: " + y); 
    } 

    void Method3(String y) { 
     System.out.println(y); 
    } 

    public static void main(String[] args) { 

     String MyVar = "2"; 
     String MyAnotherVar = "3"; 
     String MySuperVar = "4"; 
     String MySuperPublicMethodVar = "5"; 
     Main m = new Main(); 

     try { 
      Method method = Main.class.getDeclaredMethod("Method" + MyVar, int.class); //by class 
      Method anotherMethod = m.getClass().getDeclaredMethod("Method" + MyAnotherVar, String.class); //by instance 
      Method superMethod = m.getClass().getSuperclass().getDeclaredMethod("Method" + MySuperVar); //super method by instance, can be protected 
      Method superPublicMethod = m.getClass().getMethod("Method" + MySuperPublicMethodVar); //getMethod() require method defined with public, so even though sublcass calls super protected method will not works 
      try { 
       method.invoke(null, 10000);//by class 
       anotherMethod.invoke(m, "by instance"); //by instance 
       superMethod.invoke(m); //super method by instance 
       superPublicMethod.invoke(m); //super's public method by instance 
      } catch (InvocationTargetException e) { 
       throw new RuntimeException(e); 
      } 

     } catch (NoSuchMethodException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

Salida:

$ javac Main.java 
$ java Main 
by class: 10000 
by instance 
calls super protected method by instance 
calls super public method by instance 
$ 
Cuestiones relacionadas