Come una variabile statica è accessibile prima della dichiarazione?
-
02-10-2019 - |
Domanda
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
}
}
Come mai mi è permesso di utilizzare y attraverso la classe, ma non direttamente?
Quando viene definito y?
Soluzione
Le norme precise di riferimento ora di variabili di classe sono descritti nella sezione §8.3.2.3 dei JLS:
8.3.2.3 Restrizioni per l'uso di campi durante l'inizializzazione
La dichiarazione di un membro deve comparire testualmente prima del suo utilizzo solo se l'elemento è un'istanza (Rispettivamente
static
) campo di una classe o interfaccia C e tutti i seguenti condizioni:
- L'utilizzo avviene in un'istanza (rispettivamente
static
) variabile inizializzatore di C o in un'istanza (Rispettivamentestatic
) inizializzatore di C.- L'utilizzo non è sul lato sinistro di una cessione.
- L'utilizzo avviene tramite un semplice nome.
- C è la classe più interno o interfaccia racchiude l'utilizzo.
Un errore di compilazione si verifica se una delle i quattro requisiti di cui sopra non sono MET.
Ciò significa che un errore di compilazione risultati del programma di test:
class Test { int i = j; // compile-time error: incorrect forward reference int j = 1; }
, mentre i seguenti esempi di compilazioni senza errori:
class Test { Test() { k = 2; } int j = 1; int i = j; int k; }
anche se il costruttore (§8.8) per la prova si riferisce alla campo k dichiarata tre linee più tardi.
Queste restrizioni sono progettati per cattura, al momento della compilazione, circolare o altrimenti deforme inizializzazioni. Così, sia:
class Z { static int i = j + 2; static int j = 4; }
e
class Z { static { i = j + 2; } static int i, j; static { j = 4; } }
risultato in errori di compilazione. Accessi con metodi non vengono controllati in in questo modo, così:
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); } }
produce la reazione:
0
perché l'inizializzazione variabile per i utilizza il metodo della classe peek per l'accesso il valore della variabile prima j j è stato inizializzato dal suo variabile inizializzatore, a quel punto ancora ha il suo valore predefinito (§4.12.5) .
Altri suggerimenti
presumo che utilizzando la classe, il compilatore sarebbe rinviare alla ricerca per la variabile fino a quando la classe era completa, in modo che trova y, ma se proprio lo definiamo come il commento non è ancora definito in modo non riesce
Le variabili statiche sono definiti in ordine di dichiarazione della classe, durante le lezioni di carico. Quando la JVM caricherà la classe Main
, sarà definita x
, y
poi. Ecco perché non è possibile utilizzare direttamente y
durante l'inizializzazione x
, è creare qualcosa che è chiamato un di riferimento in avanti , si fa riferimento a una variabile non attualmente definito, e che è illegale per il compilatore.
Quando si utilizza Main.y
, credo che accade quanto segue:
- carico
Main
, l'inizializzazionex
si chiama - Quando si definisce
x
di essere uguali aMain.y
, il compilatore vede un riferimento a una classe, in modo che si concluderà definirex
al valore corrente dely
membro dellaMain
di classe. Si tratta questo caso, come se fosseMain
una classe diversa.
Si noti che in questo caso, durante l'inizializzazione x
, y
ha non può essere definito per il momento. Così x
avrà un valore di 0
.
Non sei autorizzato a farlo perché è privo di significato. L'eventuale unica interpretazione è che y è inizializzato a zero, e hai già due modi di dire questo. Non hai bisogno di questo.
Forse il compilatore crea i riferimenti delle variabili statiche con i valori di default con la classe nello stack, quando viene creato e quindi assegna i valori forniti.