Đó là bởi vì:
private static final int DELTA = 5;
sẽ là một thời gian biên dịch liên tục. Vì vậy, 5 đã sẵn sàng (khởi tạo) khi lớp được khởi tạo (khi nó được nạp).
Dòng đầu tiên đó được thực hiện là: public static AbstractsAndInterfaces instance = new AbstractsAndInterfaces();
Vì vậy, bây giờ bạn sẽ được chuyển tới:
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
}
Trong đoạn mã trên, DELTA
sẽ là 5 nhưng BASE
sẽ là 0 vì nó là không phải final
. Thay đổi BASE
thành final sẽ thay đổi kết quả thành 12
.
CHỈNH SỬA:
Mã mẫu để hiển thị trường hợp OP với mã 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) {
}
}
Trong đoạn mã trên, khi chương trình được chạy , sản lượng sẽ 5
và không 10
. Bây giờ, hãy xem mã byte .
Mã byte của constructor trông như thế này:
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
đang Byte cho khối init tĩnh:
tĩnh {}; mô tả:() V cờ: ACC_STATIC Code: chồng = 2, người dân địa phương = 0, args_size = 0 0: mới # 1 // lớp mẫu 3: dup 4: invokespecial # 15 // Phương thức "" :() V 7: putstatiC# 18 // Trường s: LSample; 10: bipush 10 12: putstatiC# 20 // Dòng y: Tôi 15: return LineNumberTable: dòng 3: 0 dòng 5: 10 dòng 1: 15 LocalVariableTable: Bắt đầu Chiều dài khe Tên Chữ ký
Nếu bạn kiểm tra cẩn thận, x
không được khởi tạo trong init tĩnh của lớp. Chỉ y
đang được đặt là tĩnh. Nhưng khi bạn nhìn vào hàm tạo, bạn sẽ thấy rằng hằng số 5 được sử dụng trực tiếp (iconst_5
) và được đẩy lên ngăn xếp.
Bây giờ nếu bạn thêm đoạn mã sau vào main()
:
public static void main(String[] args) {
System.out.println(Sample.x);
System.out.println(Sample.y);
}
Mã byte cho main()
sẽ là:
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;
}
Một lần nữa quan sát rằng x
đang được sử dụng như iconst_5
trong khi y
đang được tìm nạp/gọi gián tiếp.
Về cơ bản: http://stackoverflow.com/questions/27859435/java-static-final-field-initialization-order – marvin82