2009-08-23 10 views
6

Esto es una continuación de la pregunta publicada en: How to load a jar file at runtime¿Cómo se accede a un método desde un contenedor externo en tiempo de ejecución?

No estoy seguro de cómo continuar con el nivel de invocación del método. Desde mi entendimiento, del objeto clazz, usaría getMethod o getDeclaredMethod para obtener un objeto Method desde el que llamaría invoke. Por supuesto, invocar requiere una instancia. ¿Sería eso lo que se llama doRun en el código de ejemplo?

¿Necesito realizar la llamada al método doRun.run() aunque quiero ejecutar un método diferente de main (suponiendo que sea principal en el objeto doRun al que se llama con la invocación de ejecución)?

Solo para una mayor aclaración de la publicación original, pregunto: ¿DoRun.run() inicia un nuevo hilo ejecutando la instancia del objeto de clase de tipo clazz?

Gracias por ayudarme a aclarar esto.

Miré "how-should-i-load-jars-dynamically-at-runtime" (perdón, solo permitía un hipervínculo), sin embargo, esto violaba la admonición de maldad Class.newInstance en la primera publicación I referenciado

Respuesta

2

Aquí hay un código de reflexión que no se convierte en una interfaz:

public class ReflectionDemo { 

    public void print(String str, int value) { 
    System.out.println(str); 
    System.out.println(value); 
    } 

    public static int getNumber() { return 42; } 

    public static void main(String[] args) throws Exception { 
    Class<?> clazz = ReflectionDemo.class; 
    // static call 
    Method getNumber = clazz.getMethod("getNumber"); 
    int i = (Integer) getNumber.invoke(null /* static */); 
    // instance call 
    Constructor<?> ctor = clazz.getConstructor(); 
    Object instance = ctor.newInstance(); 
    Method print = clazz.getMethod("print", String.class, Integer.TYPE); 
    print.invoke(instance, "Hello, World!", i); 
    } 
} 

Escribiendo las clases reflejadas a una interfaz conocida por el código de consumidor (as in the example) es generalmente mejor porque le permite evitar la reflexión y aprovechar el sistema de tipo Java. La reflexión solo debe usarse cuando no tiene otra opción.

+0

Por lo tanto, si entiendo tu comentario siguiendo el código, con una interfaz, sé qué métodos están disponibles y puedo escribir código llamando al método directamente después de enviar el objeto de instancia de manera apropiada. ¿Es esto cierto? – Todd

+0

Por supuesto, eso supone que el código original se había compilado utilizando la interfaz, no uno que creé más tarde e intento convertir la instancia. – Todd

+0

@Todd - sí, lo tienes. El enfoque de interfaz (u otro tipo de implementación de tipo fuerte) a menudo se usa con complementos donde el código ha sido escrito para ser instanciado dinámicamente. Si está realizando introspección e invocación en clases arbitrarias, esta no es una opción. – McDowell

2

El ejemplo de código

ClassLoader loader = URLClassLoader.newInstance(
    new URL[] { yourURL }, 
    getClass().getClassLoader() 
); 
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader); 
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class); 
// Avoid Class.newInstance, for it is evil. 
Constructor<? extends Runnable> ctor = runClass.getConstructor(); 
Runnable doRun = ctor.newInstance(); 
doRun.run(); 

asume que la clase que va a cargar implementa una interfaz particular Ejecutable, y por lo tanto es reasonale para echar a ese tipo utilizando asSubclass() e invocar run().

¿Qué sabes acerca de las clases que estás cargando? ¿Puede suponer que implementan una interfaz particular? Si es así, ajuste la línea asSubClass() para hacer referencia al interafce que prefiera.

Entonces, sí, si está trabajando con métodos de instancia, cree una instancia usando el contructor, ctor en el ejemplo.

No hay inicio de un hilo en el ejemplo. La creación de un nuevo hilo simplemente habría necesitado un par de líneas de código más

Thread myThread = new Thread(doRun); 
myThread.start(); 
+0

djna - gracias por la respuesta. Lamentablemente, no puedo suponer que sé algo sobre la (s) clase (s) que puedo estar cargando. Tengo un caso de muestra que puede no ser indicativo del uso del mundo real. Tal como está, no hago una subclase, obtengo una instancia del constructor, luego sigo con el uso de getDeclaredMethod, similar a la publicación a continuación. Gracias por la otra aclaración, estaba confundido acerca de la invocación de ejecutar, pensó que eso significaba que un nuevo hilo debía comenzar, mi mal. – Todd

1

Programa de ejemplo:

impresora Proyecto:

public class Printer { 

    public void display(String printtext) 
    { 
     System.out.println(printtext); 
    } 

} 

Este proyecto se exporta como Printer.jar.

La clase de impresora tiene el método display() que toma la cadena como entrada.

código de invocación:

 URL url = new URL("file:Printer.jar"); 
     URLClassLoader loader = new URLClassLoader (new URL[] {url}); 
     Class<?> cl = Class.forName ("Printer", true, loader); 
     String printString = "Print this"; 
     Method printit = cl.getMethod("display", String.class); 
     Constructor<?> ctor = cl.getConstructor(); //One has to pass arguments if constructor takes input arguments. 
     Object instance = ctor.newInstance(); 
     printit.invoke(instance, printString); 
     loader.close(); 

Salida: Print this

Cuestiones relacionadas