Ne peut pas faire référence à "X" avant que supertype constructor ait été appelé, où x est une variable finale

considérer la déclaration suivante de la classe Java:

public class Test {

    private final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);    // <-- Compiler error: cannot reference defaultValue before supertype constructor has been called.
    }

    public Test(int i) {
        var = i;
    }
}

le code ne compilera pas, le compilateur se plaignant de la ligne que j'ai mise en évidence ci-dessus. Pourquoi cette erreur se produit-elle et quelle est la meilleure solution?

54
demandé sur Amr Bekhit 2012-06-09 23:05:16

7 réponses

la raison pour laquelle le code ne serait pas compilé initialement est parce que defaultValue est une variable d'instance de la classe Test , ce qui signifie que lorsqu'un objet de type Test est créé, une instance unique de defaultValue est également créé et attaché à cet objet particulier. Pour cette raison, il n'est pas possible de faire référence à defaultValue dans le constructeur, car ni lui, ni l'objet n'ont encore été créés.

le la solution est de faire la variable finale static :

public class Test {

    private static final int defaultValue = 10;
    private int var;

    public Test() {
        this(defaultValue);
    }

    public Test(int i) {
        var = i;
    }
}

en faisant la variable static , elle devient associée à la classe elle-même, plutôt qu'à des instances de cette classe et est partagée entre toutes les instances de Test . Les variables statiques sont créées lorsque la JVM charge la classe pour la première fois. Puisque la classe est déjà chargé lorsque vous l'utilisez pour créer une instance, la variable statique est prêt à utiliser et peut être utilisé dans la classe, y compris le constructeur.

, les Références:

75
répondu Amr Bekhit 2017-05-23 12:17:55

c'est parce que le defaultValue est un membre de Test l 'instance qui est en construction (pas encore créé)

si vous l'aviez static il a été chargé lorsque votre classe charge par classloaders

7
répondu Jigar Joshi 2012-06-09 19:08:03

règle: chaque constructeur doit exécuter le constructeur de super class avant de s'exécuter lui-même.

ainsi la première ligne de chaque constructeur est super() ou peut être ceci() et vous envoyez la valeur defaultà ce constructeur de classe qui(defaultValue) n'existe pas encore donc il y a une erreur de temps de compilation.

vous pouvez faire defaultValue comme statique et puisque la variable statique est créée comme classe est chargée à la mémoire donc defaultValue est disponible à la ligne ceci (defaultValue).

4
répondu Himanshu Mohta 2012-06-09 19:42:39

vous faites référence à une variable que dosen n'existe pas encore , s'il était statique ainsi il sera existe même avant le constructeur lui-même

mais vous allez faire face à un autre problème, comme defaultValue est devenu statique , de sorte que toutes les autres instances peuvent partager la même valeur whitch vous pouvez ne pas aimer qu'il soit,

public class Test {

    private final int defaultValue = 10; //this will be exists only after calling the contractor
    private final static int vakue2= 10; //this is exists before the contractor has been called
    private int var;

    public Test() {
       // this(defaultValue);    // this metod will not work as defaultValue doesn't exists yet
    this(value2); //this will work
    //this(10); will work
    }

    public Test(int i) {
        var = i;
    }
}
2
répondu Sherif Eldeeb 2017-08-06 20:00:36

Jusqu'à ce que votre objet n'est pas construit les valeurs par défaut des variables ne seront pas définies par conséquent si vous voulez que leurs valeurs par défaut soient définies au moment de la construction faites-les static ou explicitement les définir avant.

1
répondu amicngh 2012-06-09 20:03:37

le constructeur est appelé au moment de la création de l'objet de sorte qu'aucune référence à varable n'est reconnue par le compilateur car le compilateur n'a aucune connaissance concernant la variable d'instance car l'objet n'est pas encore créé.

0
répondu Hardik Mehta 2017-06-14 10:24:01

en fait, ce n'est pas la bonne réponse, car lors de la création d'un objet, les instructions d'initialisation des champs sont exécutées avant le constructeur. Vous pouvez déboguer le processus de création d'objet et le voir vous-même. Je me suis confus au sujet de ce problème.. par exemple, si vous changez un peu et le premier constructeur sera:

public Test(int i) {
   this(i, 0);
}
public Test (int a, int k) {
}

ça va marcher.. donc, quand le premier constructeur / null en appelle un autre, il ne fonctionne pas pour une raison étrange, même si je explicitement appeler super (); avant.

l'explication la plus pertinente serait que JVM charge les déclarations en mémoire, mais aucun constructeur n'est capable d'atteindre une variable/champ D'INSTANCE avant qu'elle ne soit entièrement exécutée.

0
répondu Giorgi Tsiklauri 2017-07-06 14:13:12