La documentation du langage Java indique:
Si un type primitif ou une chaîne est défini comme une constante et que la valeur est connue au moment de la compilation, le compilateur remplace le nom de la constante partout dans le code par sa valeur. C'est ce qu'on appelle une constante de compilation.
Ma compréhension est que si nous avons un morceau de code:
private final int x = 10;
Ensuite, le compilateur remplacera chaque occurrence de x
dans le code par littéral 10
.
Mais supposons que la constante soit initialisée au moment de l'exécution:
private final int x = getX(); // here getX() returns an integer value at run-time.
Y aura-t-il une baisse des performances (aussi négligeable soit-elle) par rapport à la constante de temps de compilation?
Une autre question est de savoir si la ligne de code ci-dessous:
private int y = 10; // here y is not final
est traité de la même manière que la constante de compilation par le compilateur?
Enfin, ce que je comprends des réponses sont:
final static
signifie constante de compilationfinal
signifie que c'est une constante mais est initialisée au moment de l'exécutionstatic
signifie initialisé au moment de l'exécutionfinal
est une variable et ne serait pas traitée comme constante.Ma compréhension est-elle correcte?
La constante de temps de compilation doit être:
Donc private final int x = getX();
n'est pas constant.
À la deuxième question private int y = 10;
n'est pas constant (non final dans ce cas), donc l'optimiseur ne peut pas être sûr que la valeur ne changera pas à l'avenir. Il ne peut donc pas l'optimiser aussi bien qu'une valeur constante. La réponse est: non, elle n'est pas traitée de la même manière que la constante de temps de compilation.
JLS fait les distinctions suivantes entre les variables et les constantes final
:
final
variablesUne variable peut être déclarée
final
. Une variablefinal
ne peut être affectée qu'à une seule fois. Il s'agit d'une erreur de compilation si une variablefinal
est affectée à moins qu'elle ne soit définitivement non affectée immédiatement avant l'affectation ( §16 (Assignation définie) ).Une fois qu'une variable
final
a été affectée, elle contient toujours la même valeur. Si une variablefinal
contient une référence à un objet, l'état de l'objet peut être modifié par des opérations sur l'objet, mais la variable fera toujours référence au même objet. Cela s'applique également aux tableaux, car les tableaux sont des objets; si une variablefinal
contient une référence à un tableau, les composants du tableau peuvent être modifiés par des opérations sur le tableau, mais la variable fera toujours référence au même tableau.Une vide
final
est une variablefinal
dont la déclaration n'a pas d'initialiseur.
Une variable constante est une variable
final
de type primitif ou de typeString
qui est initialisée avec une expression constante (- §15.28 ).
A partir de cette définition, nous pouvons discerner qu'une constante doit être:
final
String
final
)JLS ne contient pas la constante de temps de compilation de l'expression . Cependant, les programmeurs utilisent souvent les termes constante de compilation et constante de manière interchangeable .
Si une variable final
ne remplit pas les critères énoncés ci-dessus pour être considérée comme une constante, elle doit techniquement être appelée variable final
.
Selon JLS, il n'est pas nécessaire que la "variable constante" soit statique.
Donc, "variable constante" peut être statique ou non statique (variable d'instance).
Mais JLS impose d'autres exigences pour qu'une variable soit une "variable constante" (en plus d'être juste finale):
4.12.4. Variables finales (JLS)
Une variable constante est une variable finale de type primitif ou de type String qui est initialisée avec une expression constante (§15.28 ) .
Une expression de constante de compilation est une expression désignant une valeur de type primitif ou une chaîne qui ne se termine pas brusquement et se compose uniquement des éléments suivants:
Littéraux de type primitif et littéraux de type String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)
Conversion en types primitifs et conversion en type String (§15.16)
Les opérateurs unaires +, -, ~ et! (mais pas ++ ou -) (§15.15.3, §15.15.4, §15.15.5, §15.15.6)
Les opérateurs multiplicatifs *,/et% (§15.17)
Les opérateurs additifs + et - (§15.18)
Les opérateurs de décalage <<, >> et >>> (§15.19)
Les opérateurs relationnels <, <=,> et> = (mais pas instanceof) (§15.20)
Les opérateurs d'égalité == et! = (§15.21)
Les opérateurs binaires et logiques &, ^ et | (§15.22)
L'opérateur conditionnel et && et l'opérateur conditionnel ou || (§15.23, §15.24)
L'opérateur conditionnel ternaire? : (§15.25)
Expressions entre parenthèses (§15.8.5) dont l'expression contenue est une expression constante.
Noms simples (§6.5.6.1) qui font référence à des variables constantes (§4.12.4).
Noms qualifiés (§6.5.6.2) du formulaire TypeName. Identifiant faisant référence à des variables constantes (§4.12.4).
Le mot clé final
signifie qu'une variable sera initialisée une seule fois. Une réelle constante doit également être déclarée static
. Ainsi, aucun de vos exemples n'est traité comme des constantes par le compilateur. Néanmoins, le mot clé final vous indique (et au compilateur) que vos variables seront initialisées une seule fois (dans le constructeur ou littéralement). Si vous avez besoin que leurs valeurs soient attribuées au moment de la compilation, vos champs doivent être statiques.
Les performances ne sont pas vraiment affectées, mais gardez à l'esprit que les types primitifs sont immuables, une fois que vous en avez créé un, il conservera cette valeur en mémoire jusqu'à ce que le garbage collector la supprime. Donc, si vous avez une variable y = 1;
puis vous le changez en y = 2;
en mémoire, la JVM aura les deux valeurs, mais votre variable "pointera" sur cette dernière.
privé int y = 10; // ici y n'est pas définitif
est traité de la même manière que la constante de temps de compilation par le compilateur?
Non. Il s'agit d'une variable d'instance, créée, initialisée et utilisée lors de l'exécution.
Il y a peut-être une vraiment petite baisse de performance sur certaines machines pour private final int x = getX();
car cela impliquerait au moins un appel de méthode ( outre le fait que ce n'est pas une constante de temps de compilation) mais comme vous l'avez dit, ce serait négligeable alors pourquoi s'embêter?
Quant à la deuxième question: y
n'est pas finale et n'est donc pas une constante de temps de compilation, car elle peut changer au moment de l'exécution.
private final int x = getX();
Sera appelé la première fois que votre objet sera déclaré. La performance "drop" dépendra de getX()
mais ce n'est pas le genre de choses pour créer un goulot d'étranglement.
En termes simples, lors de la compilation, le compilateur remplace la référence par la valeur réelle spécifiée, au lieu d'utiliser le paramètre de référence.
public static void main(String[] args) {
final int x = 5;
}
c'est à dire. lors de la compilation, le compliant prend directement la valeur initialisée de 5 pour la comparaison plutôt que d'utiliser la variable de référence "x";