Les variables Java Final auront-elles des valeurs par défaut?

J’ai un programme comme celui-ci:

class Test { final int x; { printX(); } Test() { System.out.println("const called"); } void printX() { System.out.println("Here x is " + x); } public static void main(Ssortingng[] args) { Test t = new Test(); } } 

Si j’essaie de l’exécuter, j’obtiens une erreur de compilation car: la variable x might not have been initialized fonction des valeurs par défaut de Java.

 "Here x is 0". 

Les variables finales auront-elles des valeurs par défaut?

si je change mon code comme ça,

 class Test { final int x; { printX(); x = 7; printX(); } Test() { System.out.println("const called"); } void printX() { System.out.println("Here x is " + x); } public static void main(Ssortingng[] args) { Test t = new Test(); } } 

Je reçois une sortie en tant que:

 Here x is 0 Here x is 7 const called 

Quelqu’un peut-il s’il vous plaît expliquer ce comportement ..

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html , chapitre “Initialiser les membres de l’instance”:

Le compilateur Java copie les blocs d’initialisation dans chaque constructeur.

C’est-à-dire:

 { printX(); } Test() { System.out.println("const called"); } 

se comporte exactement comme:

 Test() { printX(); System.out.println("const called"); } 

Comme vous pouvez le voir, une fois qu’une instance a été créée, le champ final n’a pas été définitivement atsortingbué , alors que (à partir de http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html # jls-8.3.1.2 ):

Une variable d’instance finale vierge doit être définitivement atsortingbuée à la fin de chaque constructeur de la classe dans laquelle elle est déclarée; sinon, une erreur de compilation se produit.

Bien que cela ne semble pas être explicitement indiqué dans les docs (du moins, je n’ai pas pu le trouver), un dernier champ doit prendre sa valeur par défaut avant la fin du constructeur, de sorte qu’il ait une valeur prévisible si vous lisez-le avant son affectation.

Valeurs par défaut: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5

Sur votre deuxième extrait de code, x est initialisé lors de la création de l’instance, de sorte que le compilateur ne se plaint pas:

 Test() { printX(); x = 7; printX(); System.out.println("const called"); } 

Notez également que l’approche suivante ne fonctionne pas. L’utilisation de la valeur par défaut de la variable finale n’est autorisée que par une méthode.

 Test() { System.out.println("Here x is " + x); // Comstack time error : variable 'x' might not be initialized x = 7; System.out.println("Here x is " + x); System.out.println("const called"); } 

JLS dit que vous devez atsortingbuer la valeur par défaut à la variable d’instance finale vide dans le constructeur (ou dans le bloc d’initialisation qui est sensiblement le même). C’est pourquoi vous obtenez l’erreur dans le premier cas. Cependant, il ne dit pas que vous ne pouvez pas y accéder auparavant dans constructeur. Cela semble un peu bizarre, mais vous pouvez y accéder avant l’affectation et voir la valeur par défaut pour int-0.

UPD. Comme mentionné par @ I4mpi, JLS définit la règle selon laquelle chaque valeur doit être définitivement atsortingbuée avant tout access:

Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.

Cependant, il existe également une règle intéressante en ce qui concerne les constructeurs et les champs:

If C has at least one instance initializer or instance variable initializer then V is [un]assigned after an explicit or implicit superclass constructor invocation if V is [un]assigned after the rightmost instance initializer or instance variable initializer of C.

Donc, dans un second cas, la valeur x est définitivement atsortingbuée au début du constructeur, car elle contient l’affectation à la fin du constructeur.

Si vous n’initialisez pas x vous obtenez une erreur de compilation car x n’est jamais initialisé.

Déclarer x comme final signifie qu’il ne peut être initialisé que dans le constructeur ou dans le bloc d’initialisation (puisque ce bloc sera copié par le compilateur dans chaque constructeur).

La raison pour laquelle vous obtenez 0 avant que la variable ne soit initialisée est due au comportement défini dans le manuel (voir la section “Valeurs par défaut”):

Les valeurs par défaut

Il n’est pas toujours nécessaire d’atsortingbuer une valeur lorsqu’un champ est déclaré. Les champs déclarés mais non initialisés seront définis par défaut par le compilateur. En règle générale, cette valeur par défaut sera zéro ou null, selon le type de données. S’appuyer sur de telles valeurs par défaut, cependant, est généralement considéré comme un mauvais style de programmation.

Le tableau suivant résume les valeurs par défaut pour les types de données ci-dessus.

 Data Type Default Value (for fields) -------------------------------------- byte 0 short 0 int 0 long 0L float 0.0f double 0.0d char '\u0000' Ssortingng (or any object) null boolean false 

La première erreur est le compilateur se plaignant que vous avez un champ final, mais pas de code pour l’initialiser – assez simple.

Dans le deuxième exemple, vous avez du code pour lui atsortingbuer une valeur, mais la séquence d’exécution signifie que vous faites référence au champ avant et après son atsortingbution.

La valeur pré-assignée de n’importe quel champ est la valeur par défaut.

Tous les champs non finaux d’une classe sont initialisés à une valeur par défaut ( 0 pour les types de données nummeric, false pour les types booléens et null pour les types de référence, parfois appelés objects complexes). Ces champs initialisent avant qu’un constructeur (ou un bloc d’initialisation d’instance) s’exécute indépendamment du fait que les champs aient été déclarés avant ou après le constructeur.

Les champs finaux d’une classe n’ont pas de valeur par défaut et doivent être explicitement initialisés une seule fois avant qu’un constructeur de classe ait terminé son travail.

Les variables locales à l’intérieur d’un bloc d’exécution (par exemple, une méthode) n’ont aucune valeur par défaut. Ces champs doivent être explicitement initialisés avant leur première utilisation et peu importe que la variable locale soit marquée comme finale ou non.

Laissez-moi le mettre dans les mots les plus simples possible.

final variables final doivent être initialisées, ceci est requirejs par la spécification du langage. Cela dit, veuillez noter qu’il n’est pas nécessaire de l’initialiser au moment de la déclaration.

Il est nécessaire de l’initialiser avant que l’object ne soit initialisé.

Nous pouvons utiliser des blocs d’initialisation pour initialiser les variables finales. Maintenant, les blocs d’initialisation sont de deux types static et non-static

Le bloc que vous avez utilisé est un bloc d’initialisation non statique. Ainsi, lorsque vous créez un object, Runtime invoque le constructeur et appelle à son tour le constructeur de la classe parente.

Après cela, il invoquera tous les initialiseurs (dans votre cas l’initialiseur non statique).

Dans votre question, cas 1 : Même après l’achèvement du blocage de l’initialiseur, la variable finale rest non initialisée, ce qui est une erreur détectée par le compilateur.

Dans le cas 2 : l’initialiseur initialisera la variable finale, le compilateur sait donc qu’avant l’initialisation de l’object, la finale est déjà initialisée. Par conséquent, il ne se plaindra pas.

Maintenant, la question est de savoir pourquoi x prend un zéro. La raison en est que le compilateur sait déjà qu’il n’ya pas d’erreur et lors de l’invocation de la méthode init, toutes les finales seront initialisées aux valeurs par défaut et un indicateur pourra être modifié sur une instruction d’affectation similaire à x=7 . Voir l’invocation init ci-dessous:

entrer la description de l'image ici

Pour autant que je sache, le compilateur initialisera toujours les variables de classe aux valeurs par défaut (même les variables finales). Par exemple, si vous deviez initialiser un int sur lui-même, l’int serait défini sur 0. Voir ci-dessous:

 class Test { final int x; { printX(); x = this.x; printX(); } Test() { System.out.println("const called"); } void printX() { System.out.println("Here x is " + x); } public static void main(Ssortingng[] args) { Test t = new Test(); } } 

Ce qui précède imprimera ce qui suit:

 Here x is 0 Here x is 0 const called 

Si j’essaie de l’exécuter, j’obtiens une erreur de compilation car: la variable x n’a peut-être pas été initialisée en fonction des valeurs par défaut de Java.

“Ici, x vaut 0”.

Vous ne voyez pas cette sortie car vous obtenez une erreur de compilation en premier lieu. Les variables finales obtiennent une valeur par défaut, mais la spécification de langage Java (JLS) exige que vous les initialisiez à la fin du constructeur (LE: j’inclus ici les blocs d’initialisation), sinon vous obtiendrez une erreur de compilation qui empêchera votre code d’être compilé et exécuté.

Votre deuxième exemple respecte l’exigence, c’est pourquoi (1) votre code comstack et (2) vous obtenez le comportement attendu.

Dans le futur, essayez de vous familiariser avec le JLS. Il n’y a pas de meilleure source d’informations sur le langage Java.