IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Problème de classloading (?)


Sujet :

Java

  1. #1
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut Problème de classloading (?)
    Bonjour,

    je suis tombé sur un problème surprenant lié au chargement des classes et/ou peut-être à la compilation.

    Pour le reproduire, voici la marche à suivre:
    • Créer une classe ToDelete (vide)
    • Créer une classe LoadedClass contenant la méthode ci-dessous (copiez exactement le code, cf. PS en fin de message)
    • Créer un main qui se contente d'appeler le constructeur de LoadedClass (constructeur par défaut)
    • Lancer le main sans mettre la classe ToDelete dans le classpath


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        public void method()
        {
            boolean flag = false; // Peut valoir true...
     
            if (flag)
            {
                final ToDelete obj1 = new ToDelete();
            }
            else
            {
                final Object obj2 = new Object();
            }
        }
    Là, se produit un joli NoClassDefFoundError sur la classe ToDelete.
    Or, la méthode utilisant (parfois) cette classe n'a pas été appelée.

    Savez-vous à quoi cela est-il dû?

    PS: Pour vous convaincre que cela n'est pas normal, il suffit de modifier légèrement le code de la méthode et de voir qu'une erreur n'est levée. Le code fournit semble très sensible.
    Par exemple, vous pouvez:
    • supprimer le flag est mettre directement true ou false dans le if
    • supprimer le else
    • enlever la structure if et conserver les deux affectations
    • etc.

  2. #2
    Modérateur
    Avatar de wax78
    Homme Profil pro
    R&D - Palefrenier programmeur
    Inscrit en
    Août 2006
    Messages
    4 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : R&D - Palefrenier programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 4 096
    Par défaut
    Donne un peu tout le code ?

    (Sinon j'imagine qu'il y'a un import de la dite classe todelete et meme si tu t'en serts pas et qu'il ne la trouve pas -> classnotfound)
    (Les "ça ne marche pas", même écrits sans faute(s), vous porteront discrédit ad vitam æternam et malheur pendant 7 ans)

    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2004
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 184
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Savez-vous à quoi cela est-il dû?
    Je dirait que selon les optimisation du compilateur, lors du chargement de ta classe LoadedClass il peut être demandé le pré-chargement de la classe ToDelete.

  4. #4
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Citation Envoyé par wax78 Voir le message
    Donne un peu tout le code ?
    Tout le code est là, j'ai réduit mon code de reproduction au code fourni.

    La classe LoadedClass ne contient aucun champ, hérite d'Object et ne possède que la méthode du premier post.

    La classe ToDelete est vide.

    Le main fait juste:
    .

    Citation Envoyé par wax78 Voir le message
    (Sinon j'imagine qu'il y'a un import de la dite classe todelete et meme si tu t'en serts pas et qu'il ne la trouve pas -> classnotfound)
    Les imports n'existent plus une fois les classes compilées.
    De plus, les classes peuvent être dans des packages différents ou identiques, cela ne change rien.

  5. #5
    Modérateur
    Avatar de wax78
    Homme Profil pro
    R&D - Palefrenier programmeur
    Inscrit en
    Août 2006
    Messages
    4 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : R&D - Palefrenier programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2006
    Messages : 4 096
    Par défaut
    Et bien nous sommes au delà de mes compétences dans ce cas
    (Les "ça ne marche pas", même écrits sans faute(s), vous porteront discrédit ad vitam æternam et malheur pendant 7 ans)

    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par Mathieu.J Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Savez-vous à quoi cela est-il dû?
    Je dirait que selon les optimisation du compilateur, lors du chargement de ta classe LoadedClass il peut être demandé le pré-chargement de la classe ToDelete.
    En fait les règles sont précises. Mais méconnues. Dans le cas présent les optimisations du compilateur ne varient pas, il doit les faire, selon les JLS.

    En l'occurrence, la classe ToDelete est littéralement utilisée dans la méthode method(), dont on ne sait pas où et quand elle peut être appelée.
    Il est donc nécessaire de charger, préventivement, cette classe, pour être prêt quand la méthode sera appelée.

    À noter que ce n'est pas le cas en mettant if(false).
    La raison en est que false est une expression constante et que tout ce qui s'y trouve est reconnu comme code mort. Il y a deux niveaux de code morts gérés :
    - les plus évidents, qui ne compilent même pas (exemple : instructions après le return.)
    - ceux qui le sont moins, qui compilent mais comme vides. (exemple : code dans une branche conditionnelle, qui ne dépend que d'expressions constantes, et donc dont on connaît à la compilation quelle branche est parcourue. À noter qu'une expression constante peut venir d'autres classes, et donc que changer une autre classe peut changer l'effet. Ce serait gênant qu'une erreur de compilation arrive dans ce cas.)

    EDIT : sauf que tout ça n'a rien à voir avec le problème exposé. My bad -_-°.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre émérite
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Il est donc nécessaire de charger, préventivement, cette classe, pour être prêt quand la méthode sera appelée.
    Je n'ai jamais observé ce comportement (à part dans ce cas très précis). N'ayant pas lu les JLS, je ne peux pas dire que c'est normal, mais j'ai toujours vu la JVM charger les classes au moment où elle en a besoin (exécution de l'instruction) et pas au chargement de la classe.

    En ce qui concerne le code mort, cela n'entre pas en ligne de compte car en changeant le flag, le résultat est le même. De plus, à l'origine, ce n'était pas un booléen, mais un test d'existence de fichier, imprévisible à la compile.

    Pour s'en convaincre, il suffit de sortir le flag pour le même en champ de la classe, avec un setter. Ainsi, le compilateur ne pourra pas prévoir non plus la valeur du flag.

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    D'accord, je me suis trompé de problème : en effet si le main() se contente d'appeler le constructeur, en principe il n'y a pas de raison de prévoir l'appel de method().

    Sur ce point-là, je ne sais pas ce que disent les JLS, mais ça a l'air de varier.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. Problème avec classLoader et classe interne
    Par croquette06 dans le forum Langage
    Réponses: 2
    Dernier message: 30/12/2012, 00h01
  2. Problème de ClassLoader dans l'utilisation d'un plugin Eclipse
    Par hanial dans le forum Eclipse Platform
    Réponses: 0
    Dernier message: 08/07/2011, 10h47
  3. Problème de ClassLoader
    Par yotta dans le forum NetBeans
    Réponses: 14
    Dernier message: 14/05/2011, 15h55
  4. Problème avec ClassLoader.getResource()
    Par julien_lesbegueries dans le forum Général Java
    Réponses: 3
    Dernier message: 05/03/2010, 17h02
  5. Problème de classLoader dans l'utilisation d'un plugin Eclipse
    Par Cluster37 dans le forum Eclipse Platform
    Réponses: 11
    Dernier message: 12/05/2008, 17h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo