Dynamisches Laden von Klassen

Werbung
Dynamisches Laden von Klassen
●
●
Die Klasse class und die Klassen des Packages
java.lang.reflect erlauben Reflection und
Intospection.
Klassen können zur Laufzeit geladen, untersucht
und instanziert werden. Zu den dann erzeugten
Objekten können Methoden aufgerufen werden.
1
Die Klasse Class
●
●
●
●
●
Ein Objekt der Klasse Class beschreibt zur
Laufzeit eine Klasse
In diesem Objekt sind die stitschen Variblen der
Klasse angelegt.
Zu jeder im java-Programm benutzen Klasse
gibt es ein solches Objekt der Klasse Class
Ein Objekt der Klasse Class bekommt man von
einem Objekt über den Aufruf von getClass().
Die Methode Class.forName(Sting classname)
lädt eine Klasse und gibt ein Objekt der Klasse
Class zurück.
2
Untersuchen einer Klasse
●
●
●
Die Klasse und das Package java.lang.reflect
stellen Methoden und Klassen zur
Untersuchung einer Klasse bereit.
●
public Constructor<?>[] getConstructors()
●
public Method[] getDeclaredMethods()
–
public int getModifiers()
–
public Class<?>[] getParameterTypes()
. . .
So wird es möglich, die Eigenschaften einer
Klasse und ihrer Methoden komplett
auszulesen.
3
Beispiel zum Auslesen von Informationen Aus einem Objekt Class
Class C=Class.forName(ClassName);
if (C.isInterface())
{
Out=Modifier.toString(C.getModifiers())+C.getName();
}
else
{
Out=Modifier.toString(C.getModifiers())
+" class "+C.getName()+"\n"
+"extends "+C.getSuperclass().getName()+"\n";
Class[] Interfaces=C.getInterfaces();
if (Interfaces!=null & Interfaces.length>0)
{
Out+="implements ";
for (int i=0; i<Interfaces.length; i++)
{
if (i>0) Out+=", ";
Out+=Interfaces[i].getName();
}
Out+="\n";
}
Out+="{\n";
4
Field[] Fields=C.getDeclaredFields();
if (Fields.length>0)
Out+=" // DataMember\n";
for (int i=0; i<Fields.length;i++)
Out+=" "+Fields[i].toString()+";\n";
Constructor[] Constructors=C.getDeclaredConstructors();
if (Constructors.length>0)
Out+=" // Constructors\n";
for (int i=0; i<Constructors.length; i++)
Out+=" "+Constructors[i].toString()+";\n";
Method[] Methods=C.getDeclaredMethods();
if (Methods.length>0)
Out+=" // Methods\n";
for (int i=0; i<Methods.length;i++)
Out+=" "+Methods[i].toString()+";\n";
Class[] Classes=C.getClasses();
if (Classes.length>0)
Out+=" // Classes / Interfaces\n";
for (int i=0; i<Classes.length;i++)
Out+=" "+Classes[i].toString()+";\n";
Out+="}\n";
}
}
5
Laden einer Klasse
Class X=Class.forName(Name);
Instanzieren der Klasse
Calculate C=(Calculate)(X.newInstance());
Metodenaufruf
System.out.println("Y(x)="+C.fVonX(x));
Caclulate ist ein Interface
public interface Calculate
{
public double fVonX(double x);
}
6
Beispiel: Ausdrucksberechnung
●
●
●
●
Ein Programm solle in der Lage sein, beliebige
Ausrücke f(x) zu berechnen.
Lösungsansatz 1: Ausdrucksberechner mit Verfahren des rekursiven Abstiegs programmieren.
Lösungsansatz 2: Verwendung von Jcup/Jlex um
einen Interpreter für Ausdrücke generieren zu lassen
Lösungsansatz 3: Generieren eines Javaquelltextes einer Klasse mit der Methode fvonx, Übersetzung, Laden, Instanzieren der Klasse und Ausfüh7
rung der Methode fvonx.
Erzeugen des Quelltextes
●
●
Class.forName funktioniert für jede zu ladende
Klasse nur ein mal.
Workaround: fortlaufend nummerierter
Dateiname
// Hier wird der Name zusammengebaut
Name="dcalc"+Count; FileWriter O=new FileWriter(Name+".java");
O.write("class "+Name+" implements Calculate\n");
O.write("{public double fVonX(double x)“);
O.write("{return "+Command+";}}");
O.close();
8
Compilieren
Process p = Runtime.getRuntime()
.exec("javac "+Name+".java");
System.out.println("Compilation of "+Name+" started");
p.waitFor();
String line;
BufferedReader input =
new BufferedReader(new InputStreamReader
(p.getErrorStream()));
while ((line = input.readLine()) != null)
{
System.out.println(line);
}
input.close();
9
Laden und instanzieren
void calculate(double x)
{
/* Durch Einfuehrung der Funktion calculate verliert das Objekt
Class X nach jeder Ausfuehrung sein Leben wird also jedesmal
neu angelegt. */
try
{
Class X=Class.forName(Name);
Calculate C=(Calculate)(X.newInstance());
System.out.println("Y(x)="+C.fVonX(x));
}
catch(Exception e)
{System.out.println("Exception " + e);}
}
10
Der Classloader
●
●
●
●
Jede Klasse wird nur einmalig geladen.
Ausweg, Benutzung eines anderen
Classloaders: URLClassLoader
Wird mit einem Array von URLs instanziert.
Erzeugte Klasse muss in einem
Unterverzeichnis liegen, davon URL kreieren,
damit URKClassLoader instanzieren, damit
Klasse laden - fertig.
11
URL bauen
// Get the directory (URL) of the reloadable class
URL[] urls = null;
try {
// Convert the file object to a URL
File dir = new File(System.getProperty("user.dir")
+File.separator+"XFX"+File.separator);
URL url = dir.toURI().toURL();
System.out.println("URL:"+url);
urls = new URL[]{url};
} catch (MalformedURLException e) {
System.out.println(e);
}
12
Classsloader instanzieren und
rechnen
try
{
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls); //java.net
// Load in the class
Class cls = cl.loadClass("dcalc");
// Create a new instance of the new class
C = (Calculate)cls.newInstance();
}
catch (IllegalAccessException e) {System.out.println(e);}
catch (InstantiationException e) {System.out.println(e);}
catch (ClassNotFoundException e) {System.out.println(e);}
System.out.println("Y="+Command);
System.out.println("Y(x)=Y("+x+")="+C.fVonX(x));
13
Herunterladen