Ein Klassenlader ist dafür verantwortlich, eine Klasse zu laden. Aus der Datenquelle (im Allgemeinen einer Datei) liefert der Klassenlader ein Byte-Array mit den Informationen, die im zweiten Schritt dazu verwendet werden, die Klasse ins Laufzeitsystem einzubringen; das ist Linking. Es gibt vordefinierte Klassenlader und die Möglichkeit, eigene Klassenlader zu schreiben, um etwa verschlüsselte und komprimierte .class-Dateien aus Datenbanken zu laden.
Klassenladen auf Abruf
Nehmen wir zu Beginn ein einfaches Programm mit zwei Klassen:
class Person { static String NOW = java.time.LocalDateTime.now().toString();
public static void main( String[] args ) { Dog wuffi = new Dog(); } } class Dog { Person master; }
Wenn die Laufzeitumgebung das Programm Person startet, muss sie eine Reihe von Klassen laden. Das tut sie dynamisch zur Laufzeit. Sofort wird klar, dass es zumindest Person sein muss. Wenn aber die statische main(String[])-Methode aufgerufen wird, muss auch Dog geladen sein. Und da beim Laden einer Klasse auch die statischen Variablen initialisiert werden, wird auch die Klasse LocalDateTime geladen.
Zwei weitere Dinge werden nach einiger Überlegung deutlich:
- Wenn Dog geladen wird, bezieht es sich auf Person. Da Person aber schon geladen ist, muss es nicht noch einmal geladen werden.
- Unsichtbar stecken noch andere referenzierte Klassen dahinter, die nicht direkt sichtbar sind. So wird zum Beispiel Object geladen, da implizit in der Klassendeklaration von Person steht: class Person extends Object. Auch String muss geladen werden, weil String einmal in der Signatur von main(String[]) vorkommt und es der Typ von now Intern ziehen die Typen viele weitere Typen nach sich. String implementiert Serializable, CharSequence und Comparable, also müssen diese drei Schnittstellen auch geladen werden. Und so geht das weiter, je nach dem, welche Programmpfade abgelaufen werden. Wichtig ist aber zu verstehen, dass diese Klassendateien so spät wie möglich geladen werden.
Im Beispiel mit den Klassen Person und Dog lädt die Laufzeitumgebung selbstständig die Klassen (implizites Klassenladen). Klassen lassen sich auch mit Class.forName(String) über ihren Namen laden (explizites Klassenladen).
Hinweis. Um zu sehen, welche Klassen überhaupt geladen werden, lässt sich der virtuellen Maschine beim Start der Laufzeitumgebung ein Schalter mitgeben -verbose:class. Dann gibt die Maschine beim Lauf alle Klassen aus, die sie lädt.
JAR-Dateien
Große Sammlungen von Java-Klassendatein und Ressourcen werden in sogenannten Java-Archiven, kurz JAR-Dateien, zusammengefasst. Diese Dateien sind im Grunde ganz normale ZIP-Archive mit einem besonderen Verzeichnis META-INF für Meta-Dateien. Das JDK bringt im bin-Verzeichnis das Werkzeug jar zum Aufbau und Extrahieren von JAR-Dateien mit.
JAR-Dateien behandelt die Laufzeitumgebung wie Verzeichnisse von Klassendateien und Ressourcen. Wenn Java-Software ausgeliefert wird, dann bieten sich JAR-Dateien an, denn es ist einfacher, nur ein komprimiertes Archiv weiterzugehen als einen großen Dateibaum. Zudem haben Java-Archive den Vorteil, dass sie signiert werden können und illegale Änderungen auffallen.
Woher die kleinen Klassen kommen: Die Suchorte und spezielle Klassenlader
Die Laufzeitumgebung nutzt zum Laden nicht nur einen Klassenlader, sondern mehrere. Die Java-Laufzeitumgebung nutzt diese verschiedenen Klassenlader um unterschiedliche Orte festzulegen. Ein festes Schema bestimmt die Suche nach den Klassen:
- Klassen Typen wie String, Object oder Point stehen in einem ganz speziellen Archiv. Wenn ein eigenes Java-Programm gestartet wird, so sucht die virtuelle Maschine die angeforderten Klassen zuerst in diesem Archiv. Da es elementare Klassen sind, die zum Hochfahren eines Systems gehören, werden sie Bootstrap-Klassen Das Archiv mit diesen Klassen heißt oft rt.jar (für Runtime). Andere Archive können hinzukommen – wie i18n.jar, das Internationalisierungsdaten beinhaltet. Die Implementierung dieses Bootstrap-Klassenlader ist nicht öffentlich und wird von System zu System unterschiedlich sein. Ab Java 9 wird sich das grundlegend ändern.
- Ist eine Klasse keine Bootstrap-Klasse, beginnt der System-Klassenlader Applikations-Klassenlader die Suche im Klassenpfad (Classpath). Diese Pfadangabe besteht aus einer Aufzählung einzelner Klassendateien, Verzeichnisse, Klassen oder JAR-Archive, in denen die Laufzeitumgebung nach den Klassendateien sucht. Standardmäßig ist dieser Klassenpfad auf das aktuelle Verzeichnis gesetzt („.“), er lässt sich aber beliebig setzen.