Questo perché:
private static final int DELTA = 5;
sarà una costante fase di compilazione. Quindi, 5 sarà già disponibile (inizializzato) quando la classe viene inizializzata (una volta caricata).
La prima riga che viene eseguito è: public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
Così, ora si va a:
public AbstractsAndInterfaces()
{
//System.out.println(BASE);
//System.out.println(DELTA);
x = BASE + DELTA; // same as x= 0+5 i.e default value of fields + constant value 5
}
Nel codice precedente, DELTA
sarà 5 ma BASE
sarà 0 come è non final
. La modifica di BASE
in final cambia il risultato in 12
.
EDIT:
codice di esempio per mostrare lo scenario del PO con codice di byte.
public class Sample {
static Sample s = new Sample();
static final int x = 5;
static int y = 10;
public Sample() {
int z = x + y;
System.out.println(z);
}
public static void main(String[] args) {
}
}
Nel codice precedente, quando il programma è conduzione, l'uscita sarà 5
e non 10
. Ora diamo un'occhiata al codice byte .
Il codice byte del costruttore si presenta così:
p
ublic Sample();
descriptor:()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: invokespecial #24 // Method java/lang/Object."<init>
:()V
4: iconst_5 -------> // Here 5 is used directly as it is a compile time constant
5: getstatic #20 -------> // Field y:I
8: iadd
9: istore_1
10: getstatic #25 // Field java/lang/System.out:Ljav
/io/PrintStream;
13: iload_1
14: invokevirtual #31 // Method java/io/PrintStream.prin
ln:(I)V
17: return
codice byte per il blocco init statica:
statica {}; descrittore:() V bandiere: ACC_STATIC Codice: pila = 2, la gente del posto = 0, args_size = 0 0: nuovo # 1 // classe Sample 3: DUP 4: invokespecial # 15 // metodo "" :() V 7: putstatiC# 18 // Field s: LSample; 10: 10 bipush 12: putstatiC# 20 // Campo y: I 15: tornare LineNumberTable: linea 3: 0 linea 5: 10 Linea 1: 15 LocalVariableTable: Inizia Lunghezza Slot Nome Firma
Se si controlla attentamente, x
non viene inizializzato nella init statica della classe. Solo y
viene impostato come è statico. Ma quando guardi il costruttore, vedrai che la costante 5 viene utilizzata direttamente (iconst_5
) e inserita nello stack.
Ora, se si aggiunge il seguente codice nel main()
:
public static void main(String[] args) {
System.out.println(Sample.x);
System.out.println(Sample.y);
}
Il bytecode per main()
saranno:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #25 // Field java/lang/System.out:Ljav
a/io/PrintStream;
3: iconst_5 --> // No "x" but a constant value instead of "x"
4: invokevirtual #31 // Method java/io/PrintStream.prin
tln:(I)V
7: getstatic #25 // Field java/lang/System.out:Ljav
a/io/PrintStream;
10: getstatic #20 // Field y:I --> but "y" is being fetched
13: invokevirtual #31 // Method java/io/PrintStream.prin
tln:(I)V
16: return
LineNumberTable:
line 13: 0
line 14: 7
line 15: 16
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 args [Ljava/lang/String;
}
Anche in questo caso osservare che x
viene usato come iconst_5
mentre y
è essere preso/indirizzato indirettamente.
In sostanza: http://stackoverflow.com/questions/27859435/java-static-final-field-initialization-order – marvin82