web-dev-qa-db-fra.com

Class.forName () vs ClassLoader.loadClass () - Lequel utiliser pour le chargement dynamique?

Lors du chargement dynamique d’une classe, quand faut-il utiliser

Class.forName("SomeClass");

et quand dois-je utiliser

ClassLoader.getSystemClassLoader().loadClass("SomeClass");

Ou sont-ils deux façons de faire la même chose?

97
Zack

Ils sont assez différents!

Comme indiqué dans la documentation de Class.forName(String) ,

Retourne l'objet Class associé à la classe ou à l'interface avec le nom de chaîne donné. Invoquer cette méthode équivaut à: Class.forName(className, true, currentLoader)

(true fait ici référence à voulez-vous initialiser la classe? )

Par contre, ClassLoader.loadClass(String) :

Invoquer cette méthode équivaut à invoquer loadClass(name, false).

(ici, le booléen n'a rien à voir avec l'initialisation; mais si vous consultez la documentation de loadClass (String, boolean), vous verrez que tout ce qu'il fait est de charger la classe, pas de l'initialiser).

Le premier (Class.forName("SomeClass");) va:

  • utiliser le chargeur de classe qui a chargé la classe qui appelle ce code
  • initialise la classe (c'est-à-dire que tous les initialiseurs statiques seront exécutés)

L'autre (ClassLoader.getSystemClassLoader().loadClass("SomeClass");) va:

  • utiliser le chargeur de classe "system" ( qui est écrasable )
  • pas d'initialiser la classe (par exemple, si vous l'utilisez pour charger un pilote JDBC, il ne sera pas enregistré et vous ne pourrez pas utiliser JDBC!)

Supposons que vous codiez une application Web qui sera exécutée sur un conteneur tel que Tomcat. Tomcat crée un chargeur de classes pour chaque application Web (afin de pouvoir décharger les applications Web plus tard et libérer de la mémoire - vous avez besoin d'un chargeur de classes dédié pour que cela fonctionne!). Dans cette situation, vous pouvez voir que les deux appels donneront des résultats assez différents!

Pour obtenir des informations plus détaillées (et faisant autorité) sur le chargement et l'initialisation des classes, consultez les sections 12.2 et 12.4 de la dernière (3ème) édition du langage Java. Spécification.

147
Bruno Reis

Class.forName() utilise le chargeur de classe de l'appelant et initialise la classe (exécute les intitializers statiques, etc.)

loadClass est une méthode ClassLoader. Elle utilise donc un chargeur fourni explicitement et initialise la classe paresseusement (lors de la première utilisation).

Notez qu'il existe un Class.forName () qui prend également un ClassLoader.

8
Dave Newton

Ils font essentiellement la même chose. Le ClassLoader utilisé peut cependant être différent. Class.forName utilise le ClassLoader que vous obtenez de this.getClass (). GetClassLoader () alors que votre autre code spécifie l'utilisation du chargeur de classes système.

Dans la plupart des applications, il s'agira du même chargeur de classes, mais dans des environnements plus complexes tels qu'une application J2EE ou un applet, cela peut ne pas être le cas.

1
Sarel Botha

ClassLoader est une classe abstraite. Cependant, votre application est toujours chargée par un chargeur de classes. Il peut exister des chargeurs de classes personnalisés tels que le chargeur de classes réseau ou toute autre source.

D'autre part, Class en lui-même représente des classes et des interfaces et la classe Class a une fonction forName qui utilise le chargeur de classes actuel dans lequel votre application s'exécute par défaut pour charger la classe.

Voici le source de Class.forName, qui à son tour appelle le chargeur de classes appelant.

public static Class<?> forName(String className)
            throws ClassNotFoundException {
    return forName0(className, true, ClassLoader.getCallerClassLoader());
}

http://docs.Oracle.com/javase/1.4.2/docs/api/Java/lang/ClassLoader.html

http://docs.Oracle.com/javase/1.5.0/docs/api/Java/lang/Class.html#forName (Java.lang.String )

Astuce: chargeur de classe Primordial http://docs.Oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html

0
r0ast3d
  • Class.forName() charge et initialise la classe. Dans le sous-système chargeur de classe, il exécute les trois phases, à savoir les phases de chargement, de liaison et d’initialisation.

  • ClassLoader.loadClass() comportement, qui retarde l'initialisation jusqu'à ce que la classe soit utilisée pour la première fois. Dans le sous-système chargeur de classe, il n’exécute que deux phases, à savoir les phases de chargement et de liaison.

Par exemple:

class MyClass {
    static {
        System.out.println("static block in MyClass");
    }
}

public class TestCase1 {
    public static void main(String... args) throws Throwable {
        Class.forName("A");
    }
} //The above TestCase1 produce output: static block in MyClass

public class TestCase2 {
    public static void main(String... args) throws Throwable {
        ClassLoader.getSystemClassLoader().loadClass("MyClass");
    }
} //The above TestCase2 not produce any output
0
Premraj