2009-08-23 7 views
6

Ceci est la suite de la question postée dans: How to load a jar file at runtimeComment accède-t-on à une méthode à partir d'un pot externe au moment de l'exécution?

Je ne suis pas certain de la façon de passer au niveau d'invocation de la méthode. D'après ma compréhension, de l'objet clazz, j'utiliserais getMethod ou getDeclaredMethod pour obtenir un objet Method à partir duquel j'appellerais invoke. Bien sûr, invoke nécessite une instance. Serait-ce alors ce qu'on appelle doRun dans le code d'exemple? Dois-je effectuer l'appel à la méthode doRun.run() même si je veux exécuter une méthode différente de la méthode main (en supposant qu'elle soit principale sur l'objet doRun appelé avec l'invocation d'exécution)?

Juste pour plus de précisions sur la publication originale, je demande: doRun.run() démarre-t-il un nouveau thread exécutant l'instance de l'objet de classe de type clazz?

Merci de m'avoir aidé à résoudre ce problème. J'ai regardé "how-should-i-charger-jars-dynamiquement-à-runtime" (désolé, seulement autorisé un lien hypertexte), mais cela semblait violer l'avertissement de la méchanceté Class.newInstance dans le premier post I référencé

Répondre

2

Voici un code de réflexion qui ne redore pas à une interface:

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

L'écriture des classes réfléchis à une interface connue par le code du consommateur (as in the example) est généralement meilleur car il vous permet d'éviter la réflexion et de profiter du système de type Java. La réflexion ne devrait être utilisée que lorsque vous n'avez pas le choix.

+0

Donc, si je comprends votre commentaire suivant le code, avec une interface, je sais quelles méthodes sont disponibles et peut écrire du code appelant la méthode directement après avoir lancé l'objet d'instance de manière appropriée. Est-ce vrai? – Todd

+0

Bien sûr, cela suppose que le code original a été compilé en utilisant l'interface, pas un que je crée plus tard et que je tente de lancer l'instance. – Todd

+0

@Todd - oui, vous l'avez. L'interface (ou une autre implémentation de type fort) est souvent utilisée avec des plugins où le code a été écrit pour être instancié dynamiquement. Si vous faites de l'introspection et de l'invocation sur des classes arbitraires, ce n'est pas une option. – McDowell

2

L'exemple de code

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

suppose que la classe que vous chargez implémente une interface particulière Runnable, et donc il est reasonale de jeter à ce type en utilisant asSubclass() et invoquer run().

Que savez-vous des classes que vous êtes en train de charger? Pouvez-vous supposer qu'ils implémentent une interface particualr? Si oui, ajustez la ligne asSubClass() pour référencer l'interafce que vous préférez.

Ensuite, oui si vous travaillez avec des méthodes d'instance créez une instance en utilisant le constructeur, ctor dans l'exemple.

Il n'y a pas de démarrage d'un thread dans l'exemple. Création d'un nouveau thread aurait juste besoin d'un ou deux lignes plus de code

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

djna - grâce à la réponse. Malheureusement, je ne peux pas supposer que je sache quoi que ce soit au sujet de la ou des classe (s) que je pourrais charger. J'ai un exemple de cas qui peut ne pas être indicatif de l'utilisation du monde réel. En l'état, je ne sous-classe pas, j'obtiens une instance du constructeur, puis j'utilise getDeclaredMethod, similaire au post ci-dessous. Merci pour l'autre clarification, j'étais confus au sujet de l'invocation de course, pensé que cela signifiait un nouveau fil de départ - mon mauvais. – Todd

1

Exemple de programme:

Imprimante du projet:

public class Printer { 

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

} 

Ce projet est exporté sous forme Printer.jar.

La classe d'imprimante a la méthode display() qui prend la chaîne comme entrée.

Code invocation:

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

sortie: Print this

Questions connexes