Java: différence entre Class.forName et ClassLoader.loadClass

Récemment, je suis tombé sur un code qui m’a fait réfléchir. Quelle est la différence entre:

Class theClass = Class.forName("SomeImpl"); SomeImpl impl = (SomeImpl)theClass.newInstance(); 

et:

 Class theClass = ClassLoader.loadClass("SomeImpl"); SomeImpl impl = (SomeImpl)theClass.newInstance(); 

Sont-ils synonymes? L’un est-il préférable à l’autre dans certaines circonstances? Quelles sont les choses à faire et à ne pas faire avec ces deux méthodes?

Merci d’avance.

Class.forName () utilisera toujours le ClassLoader de l’appelant, tandis que ClassLoader.loadClass () peut spécifier un ClassLoader différent. Je crois que Class.forName initialise également la classe chargée, alors que l’approche ClassLoader.loadClass () ne le fait pas tout de suite (elle n’est pas initialisée avant sa première utilisation).

Je viens de trouver cet article en cherchant à confirmer mon résumé du comportement d’initialisation. Il semble que la plupart des informations que vous recherchez:

http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html

Cet usage est plutôt cool, même si je ne l’ai jamais utilisé auparavant:

 Class.forName(Ssortingng, boolean, ClassLoader) 

Il vous permet de spécifier un ClassLoader et le paramètre booléen définit si la classe doit être initialisée lorsqu’elle est chargée ou non.

La réponse de Shaun est plus ou moins correcte sauf quelques omissions / petites erreurs:

  • Class.forName associe la classe avec le ClassLoader (peu importe si un autre parent le charge pour de vrai), donc ClassLoader.findLoadedClass réussit la prochaine fois. C’est un point très, très important, la plupart des ClassLoader essayeraient la Class c = findLoadedClass(name); if (c!=null) return c; Class c = findLoadedClass(name); if (c!=null) return c; en tant que premières déclarations contournant toute la partie rechercher / rechercher. Appeler directement ClassLoader.load n’appenda pas la classe aux classes chargées.

Le cas a des implications lorsqu’il est chargé via la structure graphique de ClassLoader, c’est-à-dire qu’il n’utilise pas le parent uniquement pour rechercher en premier.

  • L’initialisation de la classe est effectuée dans loadClass du ClassLoader avec un code comme celui-ci: if (resolve) resolveClass(c); et le ClassLoader peut en fait ignorer la résolution, ce qui n’est pas recommandé mais possible.

Quelles sont les choses à faire et à ne pas faire avec ces deux méthodes?

Sauf si vous avez une idée très ClassLoader.loadClass(Ssortingng) raison pour laquelle vous souhaitez utiliser ClassLoader.loadClass(Ssortingng) , ne l’utilisez pas directement. Dans tous les autres cas, Class.forName(name, true, classLoader) toujours Class.forName(name, true, classLoader) .

Le chargement de classe global est à côté d’un art et il ne peut pas être couvert par une réponse simple (ne plaisante pas à propos de la partie d’art)

Lorsque vous utilisez Class.forName("SomeImpl") , vous obtenez la classe via le classloader actuel (c’est-à-dire le chargeur de la classe à laquelle vous avez appelé la méthode). Il va également initialiser la classe. C’est effectivement la même chose que d’appeler Class.forName("SomeImpl", true, currentLoader)currentLoader serait le chargeur de classes de l’appelant. Voir les détails ici .

La seconde méthode nécessite de choisir un chargeur de classes en premier. Ne l’écrivez pas comme ClassLoader.loadClass("SomeImpl") car ce n’est pas une méthode statique. Vous auriez besoin de quelque chose comme

 final ClassLoader cl = this.getClass().getClassLoader(); Class theClass = cl.loadClass("SomeImpl"); 

Notez que les sous-classes de ClassLoader doivent remplacer la méthode findClass plutôt que loadClass . Cela revient à appeler la méthode (protected) loadClass("SomeImpl", false) , où le second argument indique si la liaison doit être effectuée ou non.

Il existe des différences plus subtiles … La méthode loadClass attend un nom de classe binary comme spécifié par la spécification de langage Java, tandis que forName peut également être utilisé avec des chaînes représentant des types primitifs ou des classes de tableau.

De manière générale, il est préférable d’utiliser Class.forName , en spécifiant si nécessaire un chargeur de classes spécifique et s’il doit être initialisé ou non, puis laisser l’implémentation déterminer le rest. L’utilisation directe de classloaders est utile pour trouver des ressources dans un fichier jar ou sur le chemin de classe.

Cette ligne ne comstackra pas:

 Class theClass = ClassLoader.loadClass("SomeImpl"); 

car loadClass n’est pas une méthode statique de ClassLoader.

Pour résoudre ce problème, créez un object ClassLoader comme suit de l’une des trois manières suivantes:

 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Main.class.getClassLoader(); // Assuming in class Main ClassLoader classLoader = getClass().getClassLoader(); // works in any class 

puis appelez:

 Class theClass = classLoader.loadClass("SomeImpl"); 

-dbednar

La méthode loadClass() ne peut pas être appelée en tant que méthode static . Créez une sous-classe pour ClassLoader et disposez d’autres méthodes supplémentaires pour effectuer des opérations. Peut créer votre propre chargeur de classe en étendant la classe ClassLoader . Dans les deux sens, les deux sont identiques.