2009-08-23 21 views
6

Questa è una continuazione della domanda pubblicata in: How to load a jar file at runtimeCome si accede a un metodo da un jar esterno in fase di runtime?

Sono incerto su come continuare il livello di chiamata del metodo. Dalla mia comprensione, dall'oggetto clazz, avrei usato getMethod o getDeclaredMethod per ottenere un oggetto Method da cui chiamerei invoke. Ovviamente, invoke richiede un'istanza. Allora sarebbe quello che viene chiamato doRun nel codice di esempio?

È necessario eseguire la chiamata al metodo doRun.run() anche se si desidera eseguire un metodo diverso da quello principale (presupponendo che sia principale sull'oggetto doRun chiamato con l'invocazione di esecuzione)?

Solo per ulteriori chiarimenti sul post originale, chiedo: DoRun.run() avvia un nuovo thread eseguendo l'istanza dell'oggetto classe di tipo clazz?

Grazie per aver contribuito a chiarire questo per me.

Ho guardato "how-should-i-load-jars-dynamically-at-runtime" (mi dispiace, consentito solo un collegamento ipertestuale), tuttavia questo sembrava violare l'ammonizione di classe.new malvagità Instance nel primo post I riferimento.

risposta

2

Qui è un certo codice di riflessione che non gettato a un'interfaccia:

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

Scrivendo le classi riflesse a un'interfaccia nota dal codice del consumatore (as in the example) è generalmente migliore perché consente di evitare la riflessione e sfruttare il sistema di tipo Java. La riflessione dovrebbe essere usata solo quando non hai scelta.

+0

Quindi, se capisco il tuo commento seguendo il codice, con un'interfaccia, so quali metodi sono disponibili e posso scrivere codice chiamando il metodo direttamente dopo aver lanciato l'oggetto istanza in modo appropriato. È vero? – Todd

+0

Ovviamente, questo presuppone che il codice originale sia stato compilato usando l'interfaccia, non uno che creo in seguito e cerco di eseguire il cast dell'istanza. – Todd

+0

@Todd - sì, ce l'hai. L'approccio all'interfaccia (o qualche altro tipo di implementazione di tipo forte) viene spesso utilizzato con plugin in cui il codice è stato scritto per essere istanziato dinamicamente. Se stai facendo introspezione e invocazione su classi arbitrarie, questa non è un'opzione. – McDowell

2

L'esempio di codice

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

presuppone che la classe si carica implementa una particolare interfaccia Runnable, e quindi è reasonale lanciare a tale tipo utilizzando asSubclass() e richiamare run().

Che cosa sai delle classi che stai caricando? Puoi supporre che implementino un'interfaccia particolare? In tal caso, regolare la linea asSubClass() per fare riferimento all'interfetta che si preferisce.

Quindi, sì, se si sta lavorando con i metodi di istanza creare un'istanza utilizzando il contructor, ctor nell'esempio.

Nell'esempio non è stato avviato alcun thread. La creazione di un nuovo thread sarebbe solo avuto bisogno di un paio di righe di codice più

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

djna - grazie per la risposta. Sfortunatamente, non posso presumere che io sappia qualcosa sulle classi che posso caricare. Ho un caso esemplificativo che potrebbe non essere indicativo dell'uso nel mondo reale. Così com'è, non sottoclassi, ottengo un'istanza dal costruttore, quindi procedo con l'uso di getDeclaredMethod, simile al post qui sotto. Grazie per gli altri chiarimenti, ero confuso sull'invocazione della corsa, pensavo che avrebbe dovuto iniziare un nuovo thread, il mio male. – Todd

1

Programma di esempio:

Progetto stampante:

public class Printer { 

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

} 

Questo progetto viene esportato come Printer.jar.

La classe della stampante ha il metodo display() che accetta la stringa come input.

codice Invocare:

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

uscita: Print this

Problemi correlati