Comment une variable statique est accessible avant la déclaration?
-
02-10-2019 - |
Question
public class Main {
static int x = Main.y;
// static int x = y; //Not allowed; y is not defined
static int y = x;
public static void main(String[] args) {
System.out.println(x);//prints 0
}
}
Pourquoi je suis autorisé à utiliser la classe y creux, mais pas directement?
Quand y défini?
La solution
Les règles précises avant référence aux variables de classe sont décrites dans la section §8.3.2.3 des JLS:
8.3.2.3 Restrictions sur l'utilisation des champs lors de l'initialisation
La déclaration d'un membre doit apparaissent textuellement avant qu'il ne soit utilisé que si le membre est une instance (Respectivement
static
) champ d'une classe ou de l'interface C et tous les conditions suivantes sont satisfaites:
- L'utilisation se produit dans une variable instance (respectivement
static
) initialiseur de C ou dans une instance (Respectivementstatic
) initialiseur de C.- L'utilisation est pas sur le côté gauche d'une affectation.
- L'utilisation se fait par un simple nom.
- C est la classe la plus interne ou de l'interface entourant l'utilisation.
Une erreur de compilation se produit si l'un des les quatre exigences ci-dessus ne sont pas Met.
Cela signifie qu'une erreur de compilation les résultats du programme de test:
class Test { int i = j; // compile-time error: incorrect forward reference int j = 1; }
alors que les compiles exemple suivant sans erreur:
class Test { Test() { k = 2; } int j = 1; int i = j; int k; }
même si le constructeur (§8.8) pour le test se réfère à la k champ qui est déclaré trois lignes plus tard.
Ces restrictions sont destinées à prise, au moment de la compilation, circulaire ou autrement malformé initialisations. Ainsi, à la fois:
class Z { static int i = j + 2; static int j = 4; }
et
class Z { static { i = j + 2; } static int i, j; static { j = 4; } }
résultat des erreurs de compilation. Par des méthodes Accède ne sont pas vérifiées dans De cette façon, donc:
class Z { static int peek() { return j; } static int i = peek(); static int j = 1; } class Test { public static void main(String[] args) { System.out.println(Z.i); } }
produit la sortie:
0
parce que la initialiseur variable pour i utilise la méthode de classe d'accès peek la valeur de la variable j j avant a été initialisé par sa variable initialiseur, à quel point il encore a sa valeur par défaut (§4.12.5) .
Autres conseils
Je suppose qu'en utilisant la classe, le compilateur reporterait la recherche de la variable jusqu'à ce que la classe était complète, il trouve y, mais si vous définissez tout comme le commentaire il n'est pas encore défini de sorte qu'il ne
Les variables statiques sont définies dans l'ordre de déclaration dans la classe, pendant le chargement de classe. Lorsque la machine virtuelle Java chargera sera définie la classe Main
, x
, y
alors. Voilà pourquoi vous ne pouvez pas utiliser directement y
lors de l'initialisation x
, vous créez quelque chose qui est appelé référence avant , vous fait référence à une variable non définie actuellement, et c'est illégal pour le compilateur.
Lors de l'utilisation Main.y
, je pense que ce qui suit se produit:
- Vous chargez
Main
, l'initialisation dex
est appelé - Lorsque vous définissez
x
être égaux àMain.y
, le compilateur voit une référence à une classe, il mettra fin à la définitionx
à la valeur actuelle duy
membre duMain
de classe. Il traite ce cas comme siMain
était une autre classe.
Notez que dans ce cas, lors de l'initialisation x
, y
a pas été définie pour le moment. Donc x
aura une valeur de 0
.
Vous n'êtes pas autorisé à le faire parce qu'il n'a pas de sens. L'interprétation possible est que y est initialisé à zéro, et vous avez déjà deux façons de dire que. Vous n'avez pas besoin de cela.
Peut-être que le compilateur crée les références des variables statiques avec des valeurs par défaut avec la classe dans la pile, lors de sa création et affecte ensuite les valeurs fournies.