Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Sessions intra-entreprises sur demande : contact[at]mokatech.net.
Inscrivez-vous vite !

Java Quiz #34

Vous savez qu'au sein de la JVM, une classe est identifiée de manière unique par son nom complet et son classloader.

Cette règle est facile à implémenter sous la forme d'une méthode utilitaire :

  1. public class ClassUtils {
  2. public static boolean isSameClass(Class<?> class1, Class<?> class2) {
  3. if ((class1 == null) || (class2 == null)) { return false; }
  4. return (
  5. class1.getClassLoader().equals(class2.getClassLoader()) &&
  6. class1.getName().equals(class2.getName()) );
  7. }
  8. }

Il ne reste plus qu'à vérifier :

  1. System.out.println( ClassUtils.isSameClass(ClassUtils.class, ClassUtils.class) ); // true
  2. System.out.println( ClassUtils.isSameClass(String.class, ClassUtils.class) ); // false

A moins que... ?

Réponse : Ce code provoque un NullPointerException.

En effet, les classes présentes dans la bibliothèque rt.jar sont chargées par le classloader bootstrap de la JVM, qui n'a pas de représentation sous forme de classe Java.
L'opération String.class.getClassLoader() renvoie donc null !


Commentaires

1. Le lundi 1 mars 2010, 12:56 par Alexis

Perso, j'aurais plutôt fait une comparaison class1.getClassLoader() == class2.getClassLoader(). Si dans une sous-classe de ClassLoader, on redéfinit equals, on peut être dans une situation avec deux class loaders équivalents, mais différents.

2. Le lundi 1 mars 2010, 13:14 par Benoît

D'après la javadoc, si une classe est chargée par le Bootstrap classloader, la méthode getClassLoader peut renvoyer null, ce qui, dans ta méthode créerait une NPE. Pourquoi ne pas mettre dans la première condition :
class1.getClassLoader() == class2.getClassLoader() ?

3. Le lundi 1 mars 2010, 15:42 par Jean

isSameClass(null, null) => false ?

4. Le mardi 2 mars 2010, 10:02 par pjvarda

Bonjour à tous,

Je suis du même avis que Benoît.

Dans cet exemple, le second test se fait sur les classes String et ClassUtils qui sont de type respectif Class<String> et Class<ClassUtils>. Mais lorsque l'on souhaite récupérer le classLoader de ces deux classes, celui de String retourne null. Pourquoi ?

La javadoc de la méthode getClassLoader() dit ceci :

This method will return null in such implementations if this class was loaded by the bootstrap class loader. ... If this object represents a primitive type or void, null is returned.

Pourtant String n'est pas un type primitif mais un type objet.

Dixit ces liens wiki et javadoc, toutes les classes présentes dans le classpath sont, par défaut, chargées par le classLoader système. Or la classe String se trouve quant à elle dans le JAR <JAVA_HOME>/lib/rt.jar. Donc toujours suivant ces mêmes liens, son classLoader est bootstrap.

Donc le chargeur de la classe String est Bootstrap et la méthode String.getClassLoader() retourne null. Donc l'instruction (String.class).equals(ClassUtils.class) lève l'exception NullPointerException.

5. Le mardi 2 mars 2010, 10:33 par Piwaï

Du coup, j'ai une question, pardonnez mon ignorante : peut-t'on avoir deux références différentes pour la même classe au sein d'un même class loader ? Autrement dit, peux-t'on avoir le cas suivant :

ClassUtils.isSameClass(a, b) : true
a == b : false

Parce que sinon, je vois pas bien l'intérêt de mettre en place ce ClassUtils... Si quelqu'un veut bien éclairer ma lanterne sur comment cela peut-t'il arriver ;-)

Merci d'avance !

6. Le mardi 9 mars 2010, 16:14 par HollyDays

A Piwaï

Voici l'extrait de la JLS#12.2 qui répond à ta question :
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Well-behaved class loaders maintain these properties:

  • Given the same name, a good class loader should always return the same class object.
  • If a class loader ''L1'' delegates loading of a class ''C'' to another loader ''L2'', then for any type ''T'' that occurs as the direct superclass or a direct superinterface of ''C'', or as the type of a field in ''C'', or as the type of a formal parameter of a method or constructor in ''C'', or as a return type of a method in ''C'', ''L1'' and ''L2'' should return the same class object.

A malicious class loader could violate these properties. However, it could not undermine the security of the type system, because the Java virtual machine guards against this.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Autrement dit, la spécification Java recommande qu'un ClassLoader donné renvoie toujours la même instance de Class<?> pour désigner la même classe, mais ce comportement n'est pas absolument garanti.

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.