56 votes

est-il possible de désactiver l'inlining de javac dans les variables finales statiques?

La Java statique compilateur (javac) inlines statique final variables et apporte directement les valeurs de la constante de la piscine. Considérons l'exemple suivant. Classe définit des constantes (public static final variables):

public class A {
    public static final int INT_VALUE = 1000;
    public static final int STRING_VALUE = "foo";
}

Classe B utilise ces constantes:

public class B {
    public static void main(String[] args) {
        int i = A.INT_VALUE;
        System.out.println(i);
        String s = A.STRING_VALUE;
        System.out.println(s);
    }
}

Lors de la compilation de la classe B, javac obtient les valeurs de ces constantes de la classe A et inlines ces valeurs dans B.class. En conséquence, la dépendance de B avait de catégorie A au moment de la compilation est effacée à partir du bytecode. C'est un peu étrange comportement parce que vous êtes de cuisson dans les valeurs de ces constantes au moment de la compilation. Et on pourrait penser que c'est l'une des choses les plus faciles que le compilateur JIT pouvez le faire au moment de l'exécution.

Est-il possible ou cachés compilateur option qui permet de désactiver cette fonctionnalité inline comportement de javac? Pour le fond, nous sommes à la recherche à faire du bytecode de l'analyse de la dépendance de fins, et il est l'un des rares cas où le bytecode de l'analyse ne parvient pas à détecter au moment de la compilation des dépendances. Merci!

Edit: c'est une question épineuse, car normalement nous n'avons pas le contrôle de toutes les sources (par exemple, les bibliothèques de tiers que définir des constantes). Nous sommes intéressés à la détection de ces dépendances du point de vue de l'aide de l'une des constantes. Depuis que la référence est effacé du code qui utilise les constantes, il n'est pas facile à détecter, court de faire de l'analyse du code source.

46voto

DJClayworth Points 11288

L'article 93 de Java Puzzlers (Joshua Bloch) indique que vous pouvez contourner ce problème en évitant que la valeur finale soit considérée comme une constante. Par exemple:

 public class A {
  public static final int INT_VALUE = Integer.valueOf(1000).intValue();
  public static final String STRING_VALUE = "foo".toString();
}
 

Bien entendu, rien de tout cela n’est pertinent si vous n’avez pas accès au code qui définit les constantes.

14voto

Jon Skeet Points 692016

Je ne crois pas La solution de contournement la plus simple consiste à exposer ces propriétés en tant que propriétés plutôt qu'en tant que champs:

 public class A {
    private static final int INT_VALUE = 1000;
    private static final String STRING_VALUE = "foo";

    public static int getIntValue() {
        return INT_VALUE;
    }
    public static String getStringValue() {
        return STRING_VALUE;
    }
}
 

Ne pas oublier que dans certains cas , le inline est indispensable à l'utilisation de la valeur - par exemple, si vous deviez utiliser INT_VALUE en cas dans un bloc de commutation, qui doit être spécifié comme une constante valeur.

9voto

Pour arrêter la mise en ligne, vous devez définir les valeurs comme des constantes de temps non compilées (terme JLS). Vous pouvez le faire sans utiliser de fonctions et créer un minimum de bytecode en utilisant un null dans l'expression de l'initialiseur.

 public static final int INT_VALUE = null!=null?0: 1000;
 

Bien que sa génération de code soit très littérale, javac devrait optimiser cette opération en poussant un nombre entier immédiat suivi d'un magasin dans le champ statique de l'initialiseur statique.

7voto

Mark Peters Points 42201

JLS 13.4.9 traite de cette question. Leur recommandation est essentiellement d'éviter des constantes de compilation si la valeur est en aucune manière susceptible de changer.

(Une des raisons pour exiger de l'in-lining constantes, c'est que les instructions switch exiger des constantes sur chaque cas, et pas de deux de ces valeurs de constantes peut être le de même. Le compilateur vérifie dupliquer les valeurs des constantes dans un switch déclaration au moment de la compilation; la classe format de fichier ne fait pas de symbolique lien de valeurs.)

La meilleure façon d'éviter les problèmes avec les "inconstante" constantes dans largement distribué code est à déclarer compiler des constantes de temps seulement des valeurs qui sont vraiment peu de chances de jamais changement. Autres que pour les vrais constantes mathématiques, nous vous recommandons de le code source lui faire très utilisation économe de la classe des variables qui sont déclarées statique et définitive. Si la lecture seule la nature de la finale est nécessaire, une meilleure le choix est de déclarer une private static variable et un accesseur méthode pour obtenir sa valeur. Ainsi, nous recommandons:

private static int N;
public static int getN() { return N; }

plutôt que:

public static final int N = ...;

Il n'y a pas de problème avec:

public static int N = ...;

si N n'a pas besoin d'être en lecture seule.

0voto

mhagger Points 1898

jmake est un projet open-source qui prétend faire de l'ensemble de la tâche de garder la trace des dépendances entre les fichiers Java et de manière progressive de la compilation de l'ensemble minimal de fichiers requis. Il prétend gérer correctement les modifications de la statique finale des constantes, mais nécessitant parfois l'ensemble du projet à être recompilé. Il prend même en charge les modifications à une granularité plus fine que classfiles; si (par exemple) la signature d'une méthode C. m() change, alors il ne recompile les classes qui dépend en fait de m() plutôt que de toutes les classes qui utilisent C.

AVERTISSEMENT: je n'ai aucune expérience de l'utilisation de jmake.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X