Axel Rogat
Objektorientiertes Programmieren mit C++ und JAVA
 
28.3: URL-Zugriff Kapitel 28 29: Applets 
 
  28.4 Klassen über das Netz  
 

Klassen werden mit Hilfe eines Class-Loaders in die JAVA-Umgebung geladen. ClassLoader ist eine abstrakte Klasse, die die folgende Methode nicht implementiert:

Class loadClass(String name, boolean resolve);
Diese wird im Interpreter oder Browser dadurch konkretisiert, daß im lokalen Filesystem (entsprechend CLASSPATH) nach den passenden .class-Dateien gesucht wird.

Man kann nun von ClassLoader eigene Ableitungen bilden, die die Methode loadClass() so konkretisieren, daß die .class-Dateien über das Netz bezogen werden. Die eigene Klasse braucht nur die rohen Daten in ein byte-Array zu laden. Die schon konkreten Methoden von ClassLoader übernehmen den Rest. Sie interpretieren die Daten und erstellen ein Class-Objekt, über das man dann Objekte der Klasse erzeugen kann.

Damit Objekte erzeugt werden können, müssen alle offenen Referenzen in der Klasse aufgelöst werden, d.h. es müssen alle die Klassen geladen werden, die innerhalb der neuen Klasse verwendet werden. Dafür gibt es in ClassLoader die Methode resolveClass(). loadClass() erhält als zweiten Parameter ein Flag, das diese Auflösung erzwingen soll.

Beispiel: Wir schreiben einen eigenen Loader namens MyClassLoader, der im Konstruktor einen URL erhält und danach von der angegebenen Adresse Klassen lädt.

Folgendes Testprogramm versucht dann, die Klasse Chatterer zu laden und gibt deren Methoden aus. Wir verwenden hier getDeclaredMethods(), um nicht auch alle von Oberklassen geerbten Methoden aufgelistet zu bekommen:

public class loadtest { public static void main(String args[]) throws ClassNotFoundException { ClassLoader cl=new MyClassLoader( "http://www.math.uni-wuppertal.de/~axel/java/Chat"); Class c=cl.loadClass("Chatterer"); Method[] m=c.getDeclaredMethods(); for (int i=0;i<m.length;++i) System.out.println(m[i]); } }
Wenn unser Lader die Klasse nicht über den angegebenen URL erreichen kann, landet er durch eine IOException (z.B. eine MalformedURLException oder FileNotFoundException) in einem catch-Block.

Dort versucht er, die Klasse normal über das System zu beziehen (Class.forName(String)). Das ist deswegen nötig, weil beim Auflösen der Referenzen mit Sicherheit Systemklassen wie Object nachgeladen werden. Dazu wird der gleiche ClassLoader wie für die ursprüngliche Klasse verwendet, also unser eigener. Wenn auch dieser Versuch fehlschlägt, wird die von forName() ausgelöste ClassNotFoundException nach außen weitergegeben.

Außerdem vermeiden wir es, Klassen mehrfach zu laden. Von uns einmal geladene Klassen werden in eine Hashtabelle einsortiert, in der bei jeder Anfrage zunächst nachgeschaut wird.

class MyClassLoader extends ClassLoader { String host; Hashtable theClasses=new Hashtable(); public MyClassLoader(String host) { if (!host.endsWith("/")) host+="/"; this.host=host; } public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c=(Class)theClasses.get(name); if (c==null) { String s=host+name; if (!s.endsWith(".class")) s+=".class"; try { InputStream is=new URL(s).openStream(); ByteArrayOutputStream baos=new ByteArrayOutputStream(); int l; byte[] data=new byte[1024]; while ((l=is.read(data))>0) baos.write(data,0,l); data=baos.toByteArray(); c=defineClass(name,data,0,data.length); theClasses.put(name,c); } catch (Exception e) { return Class.forName(name); } } if (resolve) resolveClass(c); return c; } }
 
28.3: URL-Zugriff Startseite 29: Applets 
 
© 1998 Axel Rogat