78 votes

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(String[] args) {
        Test t = new Test();
    }

}

Si j'essaie de l'exécuter, j'obtiens une erreur de compilation comme : variable x might not have been initialized En se basant sur les valeurs par défaut de Java, je devrais obtenir le résultat ci-dessous, n'est-ce pas ?

"Here x is 0".

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

si je change mon code comme ceci,

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(String[] args) {
        Test t = new Test();
    }

}

J'obtiens le résultat suivant :

Here x is 0                                                                                      
Here x is 7                                                                                     
const called

Quelqu'un peut-il expliquer ce comportement..

61voto

sp00m Points 18767

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html , chapitre "Initialisation des 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 donc le voir, une fois qu'une instance a été créée, le champ final n'a pas été définitivement attribué tandis que (de http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.2 ):

Une variable d'instance finale vide doit être définitivement assignée à la fin de chaque constructeur de la classe dans laquelle elle se trouve. à 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 la documentation (du moins, je n'ai pas pu le trouver), un champ final doit temporairement prendre sa valeur par défaut avant la fin du constructeur, de sorte qu'il ait un champ valeur prévisible si vous le lisez avant son affectation.

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

Dans votre deuxième extrait, x est initialisé à la création de l'instance, le compilateur ne se plaint donc pas :

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

27voto

udalmik Points 2833

JLS es en disant que vous debe assigner la valeur par défaut à la variable d'instance finale vierge dans le constructeur (ou dans bloc d'initialisation ce qui est à peu près la même chose). C'est pourquoi vous obtenez l'erreur dans le premier cas. Cependant, il n'est pas dit que vous ne pouvez pas y accéder dans le constructeur avant. Cela semble un peu bizarre, mais vous pouvez y accéder avant l'affectation et voir la valeur par défaut de int - 0.

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

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 a également un 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 le deuxième cas, la valeur x es définitivement attribué au début du constructeur, car il contient l'affectation à la fin de celui-ci.

7voto

alfasin Points 19063

Si vous n'initialisez pas x vous obtiendrez une erreur de compilation puisque x n'est jamais initialisé.

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

La raison pour laquelle vous obtenez 0 imprimée avant l'initialisation de la variable est due au comportement défini dans le fichier manuel (voir : section "Valeurs par défaut").

4voto

Bohemian Points 134107

La première erreur est le compilateur qui se plaint 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 attribuer une valeur, mais la séquence d'exécution signifie que vous faites référence au champ à la fois avant et après l'avoir attribué.

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

2voto

Martin Andersson Points 1869

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

Final Les champs d'une classe ont pas de valeur par défaut et doit être initialisée explicitement une seule fois avant que le constructeur d'une classe n'ait terminé son travail.

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

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