Eine Übersetzung des Artikels wurde speziell für Studenten des Java Developer- Kurses erstellt.
In dieser Artikelserie werde ich darüber sprechen, wie die Java Virtual Machine funktioniert. Heute schauen wir uns den Mechanismus zum Laden von Klassen in der
JVM an .
Die Java Virtual Machine ist das Herzstück des Java-Technologie-Ökosystems. Es ermöglicht Java-Programmen, das Prinzip „Einmal überall ausführen“ zu implementieren. Wie andere virtuelle Maschinen ist die JVM ein abstrakter Computer. Die Hauptaufgabe der JVM besteht darin,
Klassendateien zu laden und den darin enthaltenen
Bytecode auszuführen.
Die JVM enthält verschiedene Komponenten, z. B.
einen Klassenlader , einen
Garbage Collector (automatische Speicherverwaltung), einen Interpreter, einen
JIT- Compiler und Flusssteuerungskomponenten. In diesem Artikel werden wir uns den Klassenlader ansehen.
Der Klassenladeprogramm lädt Klassendateien sowohl für Ihre Anwendung als auch für die Java-API. In die virtuelle Maschine werden nur die Java API-Klassendateien geladen, die beim Ausführen des Programms wirklich erforderlich sind.
Der Bytecode wird von der Ausführungsmaschine ausgeführt.

Was ist Klassenladen?
Das Laden von Klassen ist das dynamische Suchen und Laden von Typen (Klassen und Schnittstellen) während der Programmausführung. Typdaten befinden sich in binären Klassendateien.
Schritte zum Laden von Klassen
Das Klassenladeprogramm-Subsystem ist nicht nur für das Suchen und Importieren von binären Klassendaten verantwortlich. Es führt auch die Validierung importierter Klassen durch, weist Speicher für Klassenvariablen zu und initialisiert ihn und hilft beim Auflösen symbolischer Verknüpfungen. Diese Aktionen werden in der folgenden Reihenfolge ausgeführt:
- Laden - Suchen und Importieren von Binärdaten nach einem Typ anhand seines Namens, Erstellen einer Klasse oder Schnittstelle aus dieser Binärdarstellung.
- Verknüpfen (Verknüpfen) - Überprüfung, Vorbereitung und optional Erlaubnis:
- Überprüfung - Überprüfung der Richtigkeit des importierten Typs.
- Vorbereitung - Zuweisen von Speicher für statische Klassenvariablen und Initialisieren des Speichers mit Standardwerten.
- Lösung - Konvertieren Sie symbolische Links in direkte Links.
- Die Initialisierung ist ein Aufruf von Java-Code, der Klassenvariablen mit ihren korrekten Anfangswerten initialisiert.
Hinweis - Der Klassenlader ist neben dem Laden von Klassen auch für das Auffinden von Ressourcen verantwortlich. Eine Ressource sind einige Daten (z. B. eine ".class" -Datei, Konfigurationsdaten, Bilder), die mithilfe eines abstrakten Pfads identifiziert werden, der durch ein "/" -Zeichen getrennt ist. Ressourcen werden normalerweise mit einer Anwendung oder Bibliothek gepackt, damit sie in Anwendungs- oder Bibliothekscode verwendet werden können.
Klassenlademechanismus in Java
Anmerkung des Übersetzers - In diesem Abschnitt wird das Verhalten für Java <9 beschrieben. In Java 9+ wurden kleine Änderungen vorgenommen, die im Folgenden beschrieben werden.Java verwendet das Delegierungsmodell zum Laden von Klassen. Die Grundidee ist, dass jeder Klassenlader einen "übergeordneten" Lader hat. Wenn eine
Klasse geladen wird , „delegiert“ der Loader die Klassensuche an sein übergeordnetes Element, bevor er selbst nach der Klasse sucht.
Das Class Loader-Delegierungsmodell ist ein Diagramm von Loadern, die Ladeanforderungen aneinander weiterleiten. Die Wurzel dieses Diagramms ist der Bootstrap-Bootloader. Klassenlader werden mit einem übergeordneten Element erstellt, an das sie das Laden delegieren und an folgenden Stellen nach der Klasse suchen können:
- Cache
- Der Elternteil
- Bootloader selbst
Der Klassenladeprogramm überprüft zunächst, ob die Klasse zuvor geladen wurde. Wenn ja, wird dieselbe Klasse zurückgegeben, die beim letzten Mal zurückgegeben wurde (die im Cache gespeicherte Klasse). Wenn nicht, hat der Elternteil die Möglichkeit, die Klasse zu laden. Diese beiden Schritte werden in der Tiefe rekursiv wiederholt. Wenn das übergeordnete
Element null zurückgibt (oder eine
ClassNotFoundException auslöst ), sucht der Loader selbst nach der Klasse.
Die Klasse wird von dem Loader geladen, der dem Stamm am nächsten liegt, da das Recht zum ersten Laden der Klasse immer dem übergeordneten Loader gewährt wird. Auf diese Weise kann der Loader nur Klassen sehen, die unabhängig von seinen Eltern oder Vorfahren geladen wurden. Klassen, die von untergeordneten Ladern geladen wurden, können nicht angezeigt werden.
Die Java SE Platform API hat in der Vergangenheit zwei Klassenlader definiert:
Bootstrap-Klassenladeprogramm (Basis-, Primärladeprogramm) - Lädt Klassen aus dem Bootstrap-Klassenpfad.
Systemklassenlader ( übergeordneter
Lader) - die übergeordnete Klasse für die neuen Klassenlader und in der Regel der Klassenlader, mit dem die Anwendung geladen und ausgeführt wird.
Lader der Klasse JDK 9+
Application Class Loader - Wird häufig zum Laden von Anwendungsklassen aus einem Klassenpfad verwendet. Es ist auch der Standard-Bootloader für einige JDK-Module, die Dienstprogramme enthalten oder die Dienstprogramm-API exportieren. (
Anmerkung des Übersetzers: zum Beispiel jdk.jconsole
, jdk.jshell
usw. )
Platform Class Loader - Lädt ausgewählte (basierend auf Sicherheit / Berechtigungen) Java SE- und JDK-Module. Zum Beispiel java.sql.
Bootstrap Class Loader - Lädt die Java SE- und JDK-Kernmodule.
Diese drei integrierten Klassenlader arbeiten wie folgt zusammen:
- Der Loader der Anwendungsklasse sucht zuerst nach benannten Modulen, die für alle integrierten Loader definiert sind. Wenn für einen dieser Loader ein geeignetes Modul definiert ist, lädt dieser Loader die Klasse. Wenn die Klasse nicht in dem für einen dieser Loader definierten benannten Modul gefunden wird, delegiert der Loader der Anwendungsklasse sie an das übergeordnete Modul. Wenn die Klasse vom übergeordneten Element nicht gefunden wird, sucht der Anwendungsklassenlader im Klassenpfad danach. Im Klassenpfad gefundene Klassen werden als Mitglieder des unbenannten Moduls dieses Loaders geladen.
- Der Plattformklassenlader sucht nach benannten Modulen, die für alle integrierten Lader definiert sind. Wenn für einen dieser Loader ein geeignetes Modul definiert ist, lädt dieser Loader die Klasse. Wenn die Klasse nicht in dem für einen dieser Loader definierten benannten Modul gefunden wird, delegiert der Plattformklassenlader sie an das übergeordnete Modul.
- Der Bootstrap-Klassenlader sucht nach benannten Modulen, die für sich selbst definiert sind. Wenn die Klasse nicht in dem für den Bootstrap-Bootloader definierten benannten Modul gefunden wird, sucht der Bootstrap-Loader mit dem Parameter -Xbootclasspath / a nach Dateien und Verzeichnissen, die dem Bootstrap-Klassenpfad hinzugefügt wurden (ermöglicht das Hinzufügen von Dateien und Verzeichnissen zum Bootstrap-Klassenpfad). Im Bootstrap-Klassenpfad gefundene Klassen werden als Mitglieder des unbenannten Moduls dieses Loaders geladen.
Zum Anzeigen der integrierten Klassenlader können Sie den folgenden Code verwenden:
package ru.deft.homework; import java.sql.Date; public class BuiltInClassLoadersDemo { public static void main(String[] args) { BuiltInClassLoadersDemo demoObject = new BuiltInClassLoadersDemo(); ClassLoader applicationClassLoader = demoObject.getClass().getClassLoader(); printClassLoaderDetails(applicationClassLoader);
Wenn Sie diesen Code auf Amazon Corretto 11.0.3 ausführen, das auf mir installiert ist, erhalten Sie das folgende Ergebnis:
ClassLoader name : app ClassLoader class : jdk.internal.loader.ClassLoaders$AppClassLoader ClassLoader name : platform ClassLoader class : jdk.internal.loader.ClassLoaders$PlatformClassLoader Bootstrap classloader
Weitere Informationen zur ClassLoader-API finden Sie
hier (JDK 11) .