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

Langage Java Discussion :

[JAVAC] Optimisation indésirable à la compilation


Sujet :

Langage Java

  1. #1
    Membre à l'essai Avatar de gchauvet
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 7
    Points : 15
    Points
    15
    Par défaut [JAVAC] Optimisation indésirable à la compilation
    Bonjour à tous,

    Je rencontre un problème avec des constantes finales après la compilation des sources en une seule étape :
    Soit les deux classes A et B définies comme suit :

    Fichier A.java :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public class A
    {
        static final String S = "avant";
    }
    Fichier B.java :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class B
    {
        public static void main(String args[])
        {
            System.out.println(A.S);
        }
    }
    On compile tout ça et on exécute B :
    javac A.java B.java
    java B
    Le résultat affiché sur la console est :
    avant

    On modifie A.java comme suit :
    Fichier A.java :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public class A
    {
        static final String S = "après";
    }
    On compile A.java qui est le seul modifié et on exécute B :
    javac A.java
    java B
    Le résultat affiché sur la console est toujours :
    avant
    Alors qu’on pouvait s’attendre à obtenir
    après
    C'est franchement curieux...

    Merci par avance !

    [1] Testé avec les JDK Oracle 6/7/8

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,



    C'est normal puisqu'il s'agit de constante, c'est à dire une variable "final" initialisée en ligne avec une expression littérale (grosso-modo une chaine ou une valeur numérique).
    A la compilation la variable est directement remplacé par sa valeur.
    Le compilateur pouvant même effectuer certaines opérations dès la compilation (comme des concaténations ou des opérations mathématiques).

    Lorsqu'on modifie une constante il faut impérativement recompiler tout les fichiers qui l'utilisent pour que ce soit prix en compte.


    Si tu veux éviter ce comportement, il faut éviter d'utiliser une constante.
    Pour cela il faut que l'initialisation ne se limite pas à une expression littérale.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        static final String S = new String("avant");
    // ou bien :
        static final String S = String.valueOf("avant");
    // ou bien :
        static final String S = "avant".toString();

    a++

    PS : bien sûr il faut recompiler le tout au moins une fois pour que la modification se propage.

  3. #3
    Membre à l'essai Avatar de gchauvet
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 7
    Points : 15
    Points
    15
    Par défaut
    Salut,


    Merci, du coup je suis partie sur cette solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static final String S = null!=null ? null : "avant";

  4. #4
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Si vous ne voulez pas que le prochain collègue qui passe par là efface ce qui ne peut être que des inepties à leurs yeux, vous pouvez faire quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static final String S = nonConstant("avant");
     
    /**
     * Returns the given String, ensuring the compiler won't take it as a constant.
     *
     * Sometimes you don't want your variables to be compiled as constants but they will anyway if they respect the convention for it.
     * The result of a method call is never a constant, so just call this method when you want your String to not be compiled as a constant.
     */
    private static String nonConstant(String string) {
      return string;
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    Citation Envoyé par gchauvet Voir le message
    Merci, du coup je suis partie sur cette solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static final String S = null!=null ? null : "avant";
    Juste pour enfoncer le clou, c'est une très mauvaise solution. Si ce projet passe par les mains de quelqu'un d'autre, il changera ca au premier coup d'oeil. Et meme toi, lorsque le temps aura passé et que tu ne te rappelleras plus pourquoi tu as fait ca, tu le changeras et te disant que tu as fait un copié/collé raté. D'autre part, un compilateur un peu avancé peut très bien optimiser ce genre de chose (en fait, je suis meme étonné que cela marche puisque la condition est toujours vraie, je me serais attendu à ce que cela soit optimisé).
    A mon avis, le minimum est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static final String S = new String("avant");
    qui montre clairement que le new n'est pas un hasard (et un petit commentaire peut etre utile aussi). Sinon, la méthode de thelvin permet aussi de rendre evident que ce code n'est pas juste un vilain copié/collé.

  6. #6
    Membre à l'essai Avatar de gchauvet
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2014
    Messages : 7
    Points : 15
    Points
    15
    Par défaut
    Bonjour à tous,

    Le code en question est injecté dans les sources avant la compilation par un système d'expression régulière via Ant (j'y peux rien, c'est comme ça depuis bientôt plus de 15 ans )
    Du coup, j'ai tout de même revu l'écriture en passant par le new String("");

    Quoi qu'il en soit, je trouve cette optimisation du compilateur "déplacé"; elle aurait dû être faite par le JIT...

    Merci à tous

  7. #7
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par gchauvet Voir le message
    Quoi qu'il en soit, je trouve cette optimisation du compilateur "déplacé"; elle aurait dû être faite par le JIT...
    N'importe quoi -_-°. Le JIT ne va pas s'amuser à passer sur le chargement d'une classe, et un littéral String n'a aucune raison d'être transformé en instance plus d'une fois par la classe dans laquelle il figure, donc forcément ça arrivera au plus tard au chargement de la classe... Pas la moindre chance donc de pouvoir concerner le JIT d'une quelconque manière.

    Dis juste que toi tu aurais préféré que les constantes, ça ne marche pas d'une classe à l'autre, seulement dans la classe en cours, parce qu'en marchant d'une classe à l'autre ça veut dire que les constantes d'une classe accédées par une autre classe, ne nécessitent pas de charger cette classe pour vérifier que la constante n'a pas changé depuis la dernière compilation, et ça ne t'arrange pas.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 14/09/2012, 07h39
  2. [VS 2008] optimisation a la compilation
    Par elmcherqui dans le forum Visual Studio
    Réponses: 4
    Dernier message: 10/02/2009, 20h28
  3. commande javac sous linux pour compiler
    Par root76 dans le forum Langage
    Réponses: 2
    Dernier message: 20/02/2007, 12h46
  4. Réponses: 2
    Dernier message: 27/02/2004, 13h47
  5. [JB9][EJB]Compiler avec Make ou javac ?
    Par _gtm_ dans le forum JBuilder
    Réponses: 4
    Dernier message: 11/07/2003, 15h59

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