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?
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:
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
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).
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;
}
}
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.
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éé.
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.