Entnommen aus diesem schönen Tutorial von Sun:
Motivation
Anwendungen, die in statisch kompilierten Programmiersprachen wie C und C ++ geschrieben sind, werden in native, maschinenspezifische Anweisungen kompiliert und als ausführbare Datei gespeichert. Das Kombinieren des Codes zu einem ausführbaren nativen Code wird als Verknüpfen bezeichnet - das Zusammenführen von separat kompiliertem Code mit gemeinsam genutztem Bibliothekscode, um eine ausführbare Anwendung zu erstellen. Dies unterscheidet sich in dynamisch kompilierten Programmiersprachen wie Java. In Java bleiben die vom Java-Compiler generierten .class-Dateien unverändert, bis sie in die Java Virtual Machine (JVM) geladen werden. Mit anderen Worten, der Verknüpfungsprozess wird von der JVM zur Laufzeit ausgeführt. Klassen werden nach Bedarf in die JVM geladen. Und wenn eine geladene Klasse von einer anderen Klasse abhängt, wird auch diese Klasse geladen.
Wenn eine Java-Anwendung gestartet wird, ist die erste Klasse, die ausgeführt wird (oder der Einstiegspunkt in die Anwendung), die mit der öffentlichen statischen Void-Methode main (). Diese Klasse enthält normalerweise Verweise auf andere Klassen, und alle Versuche, die referenzierten Klassen zu laden, werden vom Klassenladeprogramm ausgeführt.
Betrachten Sie die folgende einfache Klasse, um ein Gefühl für dieses rekursive Laden von Klassen sowie für die Idee des Ladens von Klassen im Allgemeinen zu bekommen:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
Wenn Sie diese Klasse mit der Befehlszeilenoption -verbose: class ausführen, damit gedruckt wird, welche Klassen geladen werden, erhalten Sie eine Ausgabe, die wie folgt aussieht. Beachten Sie, dass dies nur eine Teilausgabe ist, da die Liste zu lang ist, um hier angezeigt zu werden.
prmpt>java -verbose:class HelloApp
[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
Wie Sie sehen, werden zuerst die für die Anwendungsklasse (HelloApp) erforderlichen Java-Laufzeitklassen geladen.
Klassenlader in der Java 2-Plattform
Die Programmiersprache Java wird ständig weiterentwickelt, um das Leben der Anwendungsentwickler jeden Tag zu vereinfachen. Dazu werden APIs bereitgestellt, die Ihr Leben vereinfachen, indem Sie sich auf die Geschäftslogik konzentrieren können, anstatt Details grundlegender Mechanismen zu implementieren. Dies wird durch die kürzlich erfolgte Änderung von J2SE 1.5 auf J2SE 5.0 deutlich, um die Reife der Java-Plattform widerzuspiegeln.
Ab JDK 1.2 ist ein in die JVM integrierter Bootstrap-Klassenladeprogramm für das Laden der Klassen der Java-Laufzeit verantwortlich. Dieser Klassenladeprogramm lädt nur Klassen, die im Boot-Klassenpfad gefunden werden. Da es sich um vertrauenswürdige Klassen handelt, wird der Validierungsprozess nicht wie bei nicht vertrauenswürdigen Klassen ausgeführt. Zusätzlich zum Bootstrap-Klassenladeprogramm verfügt die JVM über einen Erweiterungsklassenladeprogramm, das für das Laden von Klassen aus Standarderweiterungs-APIs verantwortlich ist, und ein Systemklassenladeprogramm, das Klassen aus einem allgemeinen Klassenpfad sowie aus Ihren Anwendungsklassen lädt.
Da es mehr als einen Klassenlader gibt, werden sie in einem Baum dargestellt, dessen Stamm der Bootstrap-Klassenlader ist. Jeder Klassenlader hat einen Verweis auf seinen übergeordneten Klassenlader. Wenn ein Klassenlader aufgefordert wird, eine Klasse zu laden, konsultiert er seinen übergeordneten Klassenlader, bevor er versucht, das Element selbst zu laden. Der Elternteil wiederum konsultiert seinen Elternteil und so weiter. Erst wenn alle Klassenlader der Vorfahren die Klasse nicht finden können, wird der aktuelle Klassenlader beteiligt. Mit anderen Worten wird ein Delegierungsmodell verwendet.
Die java.lang.ClassLoader-Klasse
Dies java.lang.ClassLoader
ist eine abstrakte Klasse, die von Anwendungen in Unterklassen unterteilt werden kann, die die Art und Weise erweitern müssen, in der die JVM Klassen dynamisch lädt. Mit Konstruktoren in java.lang.ClassLoader
(und seinen Unterklassen) können Sie ein übergeordnetes Element angeben, wenn Sie einen neuen Klassenlader instanziieren. Wenn Sie kein übergeordnetes Element explizit angeben, wird der Systemklassenlader der virtuellen Maschine als übergeordnetes Standardelement zugewiesen. Mit anderen Worten, die ClassLoader-Klasse verwendet ein Delegierungsmodell, um nach Klassen und Ressourcen zu suchen. Daher ist jeder Instanz von ClassLoader ein übergeordneter Klassenlader zugeordnet, sodass die Aufgabe bei der Anforderung, eine Klasse oder Ressourcen zu finden, an ihren übergeordneten Klassenlader delegiert wird, bevor versucht wird, die Klasse oder Ressource selbst zu finden. Die loadClass()
Methode des ClassLoader führt die folgenden Aufgaben aus, um beim Laden einer Klasse aufgerufen zu werden:
Wenn eine Klasse bereits geladen wurde, gibt sie sie zurück. Andernfalls wird die Suche nach der neuen Klasse an den übergeordneten Klassenlader delegiert. Wenn der übergeordnete Klassenladeprogramm die Klasse nicht findet, loadClass()
ruft er die Methode findClass()
zum Suchen und Laden der Klasse auf. Die finalClass()
Methode sucht im aktuellen Klassenladeprogramm nach der Klasse, wenn die Klasse vom übergeordneten Klassenladeprogramm nicht gefunden wurde.
Der Originalartikel enthält weitere Informationen, die Ihnen auch zeigen, wie Sie Ihre eigenen Netzwerkklassenlader implementieren, und die Ihre Frage nach dem Warum (und Wie) beantworten. Siehe auch die API-Dokumente .