Chargement des classes

Class loaders en Java

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Java charge des classes quasi dynamiquement. Quand en PHP on devait utiliser un peu partout les require_once, en Java il suffisait de préciser quelques lignes contenant les classes à charger au tout début du code. Désormais PHP s'est rapproché de ce concept grâce aux espaces de noms.

Ce quasi-dynamisme de Java peut semer le trouble dans les premiers projets écrits en ce langage. Regardons donc comment le chargement des classes est géré par la machine virtuelle de Java (JVM).

Chargement des classes en Java

Java charge des classes grâce à un outil qu'on appele class loaders. Il s'agit de traduire le nom d'une classe en bits qui pourront implémenter cette classe dans la JVM. L'introduction des classes dans l'environnement de Java a lieu à travers des classes déjà chargées. Mais comment la JVM charge la toute première classe ?

Chaque machine virtuelle possède un chargeur des classes principal. Il connaît des repértoires dans lesquels il peut trouver des classes à charger. Au premier lieu il va regarder si la classe recherchée se trouve dans les archives du boostrap. Ensuite, il regardera du côté du répertoire contenant des extensions (lib/ext dans le Java Runtime Environment standard). A la fin le chargeur vérifiera d'autres dossiers qui sont déterminés par une liste des valeurs dans la variable CLASSPATH. Ils peuvent contenir aussi bien les représentations binaires des classes Java (extensions .class) que les archives avec plusieurs classes (.jar). On peut vérifier où sont placées les classes chargées grâce à un paramètre em>-verbose:class. Analysons le résultat sur cette classe :

import java.util.HashMap;

public class Loaders {
    public static void main(String[] args) {
        System.out.println("Test of loaded classes");
        HashMap<String, String> map = new HashMap<String, String>() {{
            put("a", "1");
            put("b", "2");
            put("c", "3");
        }};
    }
}

En l'exécutant comme suit java -verbose:class Loaders on verra sur l'écran une liste des classes chargées :

[Opened C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
[Loaded sun.misc.JavaSecurityAccess from C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
[Loaded java.security.AccessControlContext$1 from C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
...
[Loaded java.io.FilePermissionCollection from shared objects file]
[Loaded java.security.AllPermission from shared objects file]
[Loaded java.security.UnresolvedPermission from shared objects file]
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded sun.misc.JavaSecurityProtectionDomainAccess from C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
[Loaded java.security.ProtectionDomain$2 from C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
[Loaded java.security.ProtectionDomain$Key from C:\Program Files (x86)\Java\jdk1.6.0_24\jre\lib\rt.jar]
[Loaded java.security.Principal from shared objects file]
[Loaded Loaders from file:/C:/cygwin/home/tests/]
Test of loaded classes
[Loaded Loaders$1 from file:/C:/cygwin/home/tests/]
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

Dans les projets plus complexes on peut vouloir personnaliser le chargement des classes en Java. Pour cela il faudra implémenter notre propre class loader. Le chargeur devra être une sous-classe de java.lang.ClassLoader. Il devra également surcharger la méthode findClass() qui s'occupe de retrouver la classe à charger.

La classe peut être chargée grâce à l'implémentation des méthodes statiques. Elles permettent d'être appelées sans besoin de créer explicitement l'instance de la classe à laquelle elles appartiennent. C'est grâce à cette spécificité que chaque classe Java peut être exécutée via la méthode statique main().

Une question ? Une remarque ?

*

*

Un conseil MySQL

Vous rencontrez un problème lors de la suppression d'un élément ou d'une table liée à des contraintes des clés étrangères. L'une des solution peut être l'annulation de la vérification de ces contraintes.


-- Au début on indique à MySQL de ne pas vérifier les contraintes des clés étrangères
SET FOREIGN_KEY_CHECKS=0;
-- Ensuite on passe à l'opération de suppression d'une table
DROP TABLE ma_table;
-- A la fin (ou au moment voulu) on restaure la vérification des contraintes
SET FOREIGN_KEY_CHECKS=1;

Vous pouvez en savoir plus sur FOREIGN_KEY_CHEKS dans la documentation du MySQL.