Tiré de ce joli tutoriel de Sun:
Motivation
Les applications écrites dans des langages de programmation compilés statiquement, tels que C et C ++, sont compilées dans des instructions natives spécifiques à la machine et enregistrées sous forme de fichier exécutable. Le processus de combinaison du code en un code natif exécutable est appelé liaison - la fusion d'un code compilé séparément avec un code de bibliothèque partagé pour créer une application exécutable. Ceci est différent dans les langages de programmation compilés dynamiquement tels que Java. En Java, les fichiers .class générés par le compilateur Java restent tels quels jusqu'à ce qu'ils soient chargés dans la machine virtuelle Java (JVM) - en d'autres termes, le processus de liaison est effectué par la JVM au moment de l'exécution. Les classes sont chargées dans la machine virtuelle Java selon les besoins. Et lorsqu'une classe chargée dépend d'une autre classe, cette classe est également chargée.
Lorsqu'une application Java est lancée, la première classe à exécuter (ou le point d'entrée dans l'application) est celle avec la méthode publique static void appelée main (). Cette classe a généralement des références à d'autres classes, et toutes les tentatives de chargement des classes référencées sont effectuées par le chargeur de classe.
Pour avoir une idée de ce chargement de classe récursif ainsi que de l'idée de chargement de classe en général, considérez la classe simple suivante:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
Si vous exécutez cette classe en spécifiant l'option de ligne de commande -verbose: class, afin qu'elle imprime les classes en cours de chargement, vous obtiendrez une sortie qui se présente comme suit. Notez qu'il ne s'agit que d'une sortie partielle car la liste est trop longue pour être affichée ici.
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]
Comme vous pouvez le voir, les classes d'exécution Java requises par la classe d'application (HelloApp) sont chargées en premier.
Chargeurs de classes dans la plate-forme Java 2
Le langage de programmation Java ne cesse d'évoluer pour faciliter la vie des développeurs d'applications au quotidien. Cela se fait en fournissant des API qui vous simplifient la vie en vous permettant de vous concentrer sur la logique métier plutôt que sur les détails de mise en œuvre des mécanismes fondamentaux. Ceci est évident par le récent changement de J2SE 1.5 vers J2SE 5.0 afin de refléter la maturité de la plateforme Java.
À partir de JDK 1.2, un chargeur de classe d'amorçage intégré à la JVM est responsable du chargement des classes de l'environnement d'exécution Java. Ce chargeur de classe charge uniquement les classes qui se trouvent dans le chemin des classes de démarrage, et comme il s'agit de classes approuvées, le processus de validation n'est pas effectué comme pour les classes non approuvées. En plus du chargeur de classe d'amorçage, la machine virtuelle Java dispose d'un chargeur de classe d'extension responsable du chargement des classes à partir des API d'extension standard, et d'un chargeur de classe système qui charge les classes à partir d'un chemin de classe général ainsi que vos classes d'application.
Puisqu'il y a plus d'un chargeur de classe, ils sont représentés dans une arborescence dont la racine est le chargeur de classe bootstrap. Chaque chargeur de classe a une référence à son chargeur de classe parent. Lorsqu'un chargeur de classe est invité à charger une classe, il consulte son chargeur de classe parent avant de tenter de charger l'élément lui-même. Le parent consulte à son tour son parent, et ainsi de suite. Ce n'est donc qu'après que tous les chargeurs de classes ancêtres n'ont pas pu trouver la classe que le chargeur de classes actuel est impliqué. En d'autres termes, un modèle de délégation est utilisé.
La classe java.lang.ClassLoader
Le java.lang.ClassLoader
est une classe abstraite qui peut être sous-classée par les applications qui doivent étendre la manière dont la JVM charge dynamiquement les classes. Les constructeurs dans java.lang.ClassLoader
(et ses sous-classes) vous permettent de spécifier un parent lorsque vous instanciez un nouveau chargeur de classe. Si vous ne spécifiez pas explicitement un parent, le chargeur de classe système de la machine virtuelle sera affecté en tant que parent par défaut. En d'autres termes, la classe ClassLoader utilise un modèle de délégation pour rechercher des classes et des ressources. Par conséquent, chaque instance de ClassLoader a un chargeur de classe parent associé, de sorte que lorsqu'il est demandé de trouver une classe ou des ressources, la tâche est déléguée à son chargeur de classe parent avant de tenter de trouver la classe ou la ressource elle-même. La loadClass()
méthode du ClassLoader effectue les tâches suivantes, dans l'ordre, lorsqu'elle est appelée pour charger une classe:
Si une classe a déjà été chargée, elle la renvoie. Sinon, il délègue la recherche de la nouvelle classe au chargeur de classe parent. Si le chargeur de classe parent ne trouve pas la classe, loadClass()
appelle la méthode findClass()
pour rechercher et charger la classe. La finalClass()
méthode recherche la classe dans le chargeur de classe actuel si la classe n'a pas été trouvée par le chargeur de classe parent.
Il y en a plus dans l'article original, qui vous montre également comment implémenter vos propres chargeurs de classe réseau, ce qui répond à votre question de savoir pourquoi (et comment). Voir également la documentation de l' API .