Это потому, что:
private static final int DELTA = 5;
будет время компиляции постоянной. Таким образом, 5 уже будут доступны (инициализированы), когда класс будет инициализирован (после его загрузки).
Первая линия, которая запускается на выполнение является: public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
Итак, теперь вы будете ехать на:
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
}
В приведенном выше коде, DELTA
будет 5, но BASE
будет 0, как это не final
. Изменение BASE
в окончательном варианте изменит результат на 12
.
EDIT:
Пример кода, чтобы показать сценарий Ор с байт-код.
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) {
}
}
В приведенном выше коде, когда программа запустить, выход будет 5
и не 10
. Теперь давайте посмотрим на байт-код .
байт-код конструктора выглядит следующим образом:
р
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
байт-код для статического блока инициализации:
статическая {}; дескриптора:() V флаги: ACC_STATIC Код: стек = 2, местные жители = 0, args_size = 0 0: новый # 1 // Класс Sample 3: DUP 4: invokespecial # 15 // Метод "" :() V 7: putstatiC# 18 // Поле s: LSample; 10: bipush 10 12: putstatiC# 20 // Поле у: I 15: возвращение LineNumberTable: линия 3: 0 линия 5: 10 линия 1: 15 LocalVariableTable: Начало Длина Slot Имя Подпись
Если вы тщательно проверите, x
не инициализируется в статическом инициализации класса. Только y
устанавливается как статичный. Но когда вы посмотрите на конструктор, вы увидите, что константа 5 используется непосредственно (iconst_5
) и вставляется в стек.
Теперь, если добавить следующий код в main()
:
public static void main(String[] args) {
System.out.println(Sample.x);
System.out.println(Sample.y);
}
байт-код для main()
будет:
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;
}
Снова заметим, что x
используется как iconst_5
тогда y
это время Принято/указано косвенно.
По существу: http://stackoverflow.com/questions/27859435/java-static-final-field-initialization-order – marvin82