2011-01-22 10 views
47

Me gustaría invocar un método estático privado. Tengo su nombre He oído que se puede hacer utilizando el mecanismo de reflexión de Java. ¿Cómo puedo hacerlo?¿Cómo invoco un método estático privado usando reflection (Java)?

EDIT: Un problema que encontré al intentar invocar el método es cómo especificar el tipo de su argumento. Mi método recibe un argumento y su tipo es Map. Por lo tanto, no puedo hacer Map<User, String>.TYPE (En tiempo de ejecución no existe Map por el borrado de Java Type). ¿Hay alguna otra forma de obtener el método?

+1

intento 'MyClass.class.getDeclaredMethod ("myMethod", Map.class);' para su caso – Cratylus

+0

Curiosamente el genérico la información del método todavía está disponible en tiempo de ejecución. 'Method.getGenericParameterTypes' –

Respuesta

79

Digamos que quiere llamar a MyClass.myMethod (int x);

Method m = MyClass.class.getDeclaredMethod("myMethod", Integer.TYPE); 
m.setAccessible(true); //if security settings allow this 
Object o = m.invoke(null, 23); //use null if the method is static 
+0

Gracias. Mi método recibe un parámetro y su tipo es Map . Por lo tanto, no puedo hacer 'Map .TYPE'. ¿Hay alguna otra forma de obtener el método? – snakile

+6

@snakile: prueba 'MyClass.class.getDeclaredMethod (" myMethod ", Map.class);' para tu caso – Cratylus

+3

Todo lo que me enseñaron en la Universidad era una mentira ... – rsy

0
Object insecure; //This needs to be an initialized reference 

Class c = insecure.getClass(); 
Method m = c.getMethod(name, parameterTypes); //Fill the name and types in 
m.setAccessible(true); 
m.invoke(insecure, parameters); //Fill in the parameters you would like 

Hay una serie de excepciones comprobadas que puedan ser lanzados. Tanto los parameterTypes como los parámetros son argumentos de elipse (longitud variable), llénelos según sea necesario. La JVM por especificación tiene una convención de llamadas fuertemente tipada, por lo que debe conocer los tipos de parámetros.

Dicho esto, a menos que esté escribiendo algún tipo de contenedor de aplicaciones, contenedor de componentes de servidor, sistema similar a RMI o lenguaje basado en JVM, debe evitar hacerlo.

9

invocación principal de reflection tutorial

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

public class InvokeMain { 
    public static void main(String... args) { 
    try { 
     Class<?> c = Class.forName(args[0]); 
     Class[] argTypes = new Class[] { String[].class }; 
     Method main = c.getDeclaredMethod("main", argTypes); 
     String[] mainArgs = Arrays.copyOfRange(args, 1, args.length); 
     System.out.format("invoking %s.main()%n", c.getName()); 
     main.invoke(null, (Object)mainArgs); 

     // production code should handle these exceptions more gracefully 
    } catch (ClassNotFoundException x) { 
     x.printStackTrace(); 
    } catch (NoSuchMethodException x) { 
     x.printStackTrace(); 
    } catch (IllegalAccessException x) { 
     x.printStackTrace(); 
    } catch (InvocationTargetException x) { 
     x.printStackTrace(); 
    } 
    } 
} 
2

No, no se puede decir Map<K,V>.class. Esto se debe a tipo borrado. En tiempo de ejecución, no hay tal cosa.

Afortunadamente, usted puede decir simplemente viejo Map.class. Es todo lo mismo en tiempo de ejecución.

Si le molestan las advertencias, busque otras preguntas relacionadas con los genéricos y el tipo de borrado, aquí encontrará una gran cantidad de información sobre el tema.

+0

+1 para señalar tipo borrado – snakile

1

Uso un único método que encapsula el método de destino y luego lo invoca. Probablemente tiene algunas limitaciones, por supuesto. Aquí está el método puesto en una clase y su prueba unitaria:

public class Invoker { 
/** 
* Get method and invoke it. 
* 
* @author jbetancourt 
* 
* @param name of method 
* @param obj Object to invoke the method on 
* @param types parameter types of method 
* @param args to method invocation 
* @return return value 
* @throws Exception for unforseen stuff 
*/ 
public static final <T> Object invokeMethod(final String name, final T obj, 
    final Class<?>[] types, final Object... args) throws Exception { 

    Method method = obj.getClass().getDeclaredMethod(name, types); 
    method.setAccessible(true); 
    return method.invoke(obj, args); 
} 

/** 
* Embedded JUnit tests. 
*/ 
@RunWith(JUnit4.class) 
public static class InvokerTest { 
    /** */ 
    @Test 
    public void testInvoke() throws Exception { 
     class TestTarget { 
      private String hello() { 
       return "Hello world!"; 
      } 
     } 

     String actual = (String) Invoker.invokeMethod("hello", 
       new TestTarget(), new Class<?>[] {}); 
     String expected = "Hello world!"; 
     assertThat(actual, is(expected)); 

    } 
} 

}

Cuestiones relacionadas