2016-04-01 12 views
1

Ich versuche, einen Code zu erstellen, um eine Klasse dynamisch zu laden und sie zum Erstellen neuer Instanzen und zum Ausführen von Umwandlungen zu verwenden. Ich kann eine Instanz aus der neu geladenen Klasse mit dieser Methode erstellen: myClass.newInstance();. Aber ich kann es nicht als Typ benutzen. Zum Beispiel: myClass myObj = new myClass(); Es funktioniert nicht. Ist es irgendwie möglich, etwas zu leisten?Ist es möglich, eine Klasse dynamisch zu laden und sie als Typ zu verwenden?

Dies ist der Code, den ich zu machen versuchte:

URL classUrl; 
classUrl = new URL("file:///C:/classes/"); 
URL[] classUrls = { classUrl }; 
URLClassLoader ucl = new URLClassLoader(classUrls); 
Class c = ucl.loadClass("Operation"); 
Class MyIn = ucl.loadClass("MyInter"); 
Object o = c.newInstance(); //IT WORKS 
System.out.println(((MyIn) o).sum(2, 4)); //IT DOES NOT WORK. Message: MyIn cannot be resolved to a type 
+0

Fragen Sie, warum Sie die Klasse nicht zur Kompilierzeit verwenden können, wenn Sie sie nach der Kompilierzeit geladen haben? –

+0

Sie haben Recht, aber ich möchte eine Möglichkeit, es dynamisch zu tun, MyIn dynamisch zu laden, anstatt es in das Projekt zu setzen –

+0

'MyIn' in Ihrem Code ist ein Variablenname und Sie später versuchen,' o' auf den Schnittstellentyp 'zu werfen MyIn' - notiere die gleichen Charaktere hier! Ändern Sie den Namen der Variablen 'MyIn' in etwas Java-typischeres wie' myIn'. Sie könnten auch versuchen, eine Instanz von 'MyIn' mit einer Instanz von' MyIn instance = MyIn.getClass() .cast (o); 'zu übergeben und dann in Ihrer Anwendung als jede andere nicht dynamisch geladene Instanz von' MyIn' zu verwenden –

Antwort

5

Da Sie nicht wissen, Myin bei der Kompilierung, müssen Sie Reflexion nicht nur verwenden, um die Klasse zu instanziieren, wie Sie tun, sondern auch Methoden aufrufen.

Etwas entlang der Linien von:

MyIn.getDeclaredMethod("sum",Integer.TYPE,Integer.TYPE).invoke(o,2,4); 

Siehe zum Beispiel https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

+1

Sie können ihre Methoden direkt aufrufen, wenn sie sich in einer Schnittstelle befinden, die zur Kompilierungszeit bekannt ist und von der dynamisch geladenen Klasse implementiert wird. –

+0

MyIn ist eine Schnittstelle, die ich versuche zu laden. Deshalb versuche ich eine Besetzung zu machen. Das Internface hat eine Deklaration der Methode 'sum'.Wenn Sie die von mir angegebene Zeile ausführen, wird ein neuer Fehler angezeigt: Caught exception: java.lang.NoSuchMethodException: MyEx.sum() –

+0

Siehe API für getDeclaredMethod, benötigt Parametertypen. –

1

Sie können direkt eine Klasse nicht zur Compile-Zeit verwenden, die Sie später zur Laufzeit laden.

Allerdings können Sie arbeiten direkt durch einen oder mehrere Schnittstellen von den geladenen Klassen implementiert. In der Regel sind die Schnittstellen selbst im Kompilierungszeit-Klassenpfad des Ladecodes und des geladenen Codes enthalten.

Die gemeinsam genutzten Schnittstellen definieren die erwartete Interaktion zur Kompilierzeit. Der geladene Code definiert ein Verhalten zur Laufzeit.

Zum Beispiel könnten Sie diese dynamisch geladenen Klasse laden:

public class Operation implements MyInterface { ... } 

Und dann mit ihm über eine gemeinsame Schnittstelle interagieren:

Class c = ucl.loadClass("mypackage.Operation"); 
Object o = c.newInstance(); //IT WORKS 
MyInterface operation = (MyInterface) o; 

Jetzt können Sie interagieren direkt mit den Methoden durch die gemeinsame Schnittstelle.

System.out.println(operation.sum(2, 4)); 

Konstrukteurs

For example: myClass myObj = new myClass(); It doesn't work. Is it possible to perform somehow?

Sie können eine Fabrik mit dem Namen Konstrukteuren im dynamisch geladenen Code erstellen. Die Fabrik würde auch eine gemeinsame Schnittstelle implementieren.

Class cFactory = ucl.loadClass("mypackage.MyFactory"); 
MyFactoryInterface factory = (MyFactoryInterface) cFactory.newInstance();  
MyInterface myObj = factory.makeOperation(); 
+0

Andy, danke für die Antwort. Wie kann ich diese Schnittstelle verwenden, ohne sie in mein Projekt zu integrieren? Weil mein Code technisch nicht weiß, dass meine neu geladene Klasse eine Schnittstelle namens "MyInterface" implementiert hat, richtig? Mein Code kann diese Schnittstelle nicht sehen, wenn ich sie dort deklariere. Diese geladene Klasse wurde ebenfalls dynamisch kompiliert. Und was generiert wurde, war nur die .class-Datei. Ich habe 'Operation.java' dynamisch kompiliert und habe jetzt in meinem Ordner 'Operation.java' und 'Operation.class'. Ich nehme Operation.class und ich lade es. Aber wie kann ich die Schnittstelle "MyInter" nehmen, die Operation implementiert? –

+1

@ AraújoFilho Da Sie die Schnittstelle so deklariert haben, wie Sie 'Operation' geschrieben haben, muss die Schnittstelle irgendwo anders sein, sonst' Operation' sollte nicht einmal kompiliert werden. Üblicherweise (wie in Plug-in-fähigen Anwendungen) gibt es im Hauptcode bereits eine Schnittstelle, um dynamisch geladene Klassen aufrufen zu können, die mindestens die von der Schnittstelle spezifizierten Methoden implementieren müssen, sonst könnte es schwierig werden, dynamisch geladene Klassen auszuführen per se –

+0

Thx @RomanVottner. Ich hab es jetzt. Gibt es also keine Möglichkeit, eine Schnittstelle dynamisch zu laden? –

Verwandte Themen