Câu trả lời ngắn
Khi khởi tạo của lớp bắt đầu, k
sẽ có giá trị ban đầu của 0.
Khối tĩnh (vì nó đi trước sự phân công trong tờ khai) sau đó được thực hiện, và k
sẽ được chỉ định 2.
Sau đó, trình khởi tạo trong khai báo được thực hiện và k
sẽ được chỉ định 1.
dài giải thích
Chúng ta hãy sử dụng this example, vì ví dụ của bạn là một chút đơn giản:
class TestInitOrder {
static {
System.out.println(TestInitOrder.stat1);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
str = "something";
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
private static final int stat1 = 10;
static final String str2 = "sdfff";
static String str = "crap";
private static int stat2 = 19;
static final Second second = new Second();
static final int lazy;
static {
lazy = 20;
}
static {
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
public static void main(String args[]) {
}
}
class Second {
public Second() {
System.out.println(TestInitOrder.second);
}
}
Theo Java Language Specification, từ section 4.12.5:
Mỗi biến trong một chương trình phải có giá trị trước khi giá trị của nó được sử dụng:
- Mỗi biến lớp, ví dụ biến, hoặc một thành phần mảng được khởi tạo với giá trị mặc định khi nó được tạo ra
(Các dòng sau từ đặc điểm kỹ thuật xác định giá trị mặc định cho tất cả các loại, về cơ bản một số hình thức 0, chẳng hạn như 0
, 0.0d
, null
, false
, vv)
vì vậy, trước khi lớp được khởi tạo (do một trong these reasons), các biến sẽ tổ chức một giá trị ban đầu.
Theo detailed initialization procedure (chỉ các bước thú vị được trích dẫn ở đây, và tôi nhấn mạnh):
6. [...] Sau đó, khởi tạo final
biến lớp và lĩnh vực giao diện có giá trị là thời gian biên dịchbiểu thức không đổi (§8.3.2.1, §9.3.1, §13.4.9, §15.28).
[...]
9. Tiếp theo, thực hiện một trong hai initializers lớp biến và initializers tĩnh của lớp, hoặc initializers lĩnh vực giao diện, theo thứ tự văn bản, như thể chúng là một khối duy nhất .
Chúng ta hãy nhìn ở bước 6, với 4 final
biến lớp: stat1
, str2
, second
, lazy
.
Kể từ 10
là biểu hiện liên tục, và như vậy là "sdfff"
, và do sự tự thực hiện, đó là không thể quan sát giá trị ban đầu cho str2
và stat1
. Để thực hiện một quan sát, sớm nhất bạn có thể làm là ở bước 9.
Trường hợp second
chứng minh rằng khi mặt bên phải không phải là biểu thức hằng số biên dịch, thì giá trị ban đầu của nó có thể nhìn thấy được.
Trường hợp lazy
khác, vì việc gán được thực hiện trong khối tĩnh và do đó xảy ra ở bước 9 - vì vậy có thể quan sát giá trị ban đầu của nó. (Vâng, trình biên dịch kiểm tra cẩn thận rằng lazy
được gán chính xác một lần).
Sau khi khởi tạo biến lớp cuối cùng với biểu thức hằng số biên dịch, việc thực hiện các khối tĩnh và phần còn lại của trình khởi tạo.
Như bạn có thể nhìn thấy từ ví dụ này, các khối tĩnh và khởi xảy ra theo thứ tự văn bản - chứng minh với việc sử dụng str
biến - đó là lần đầu tiên in ra như null
, sau đó something
, sau đó crap
.
Đầu tiên, k sẽ được gán giá trị mặc định, sau đó từ trên cùng, mã tĩnh sẽ được chạy và 2 sẽ được gán, sau đó 1 sẽ được chỉ định. Sau đó, chức năng chính được gọi và in ra k. 'static int k = 1' là khai báo' static int k; 'hiệu quả, sau đó' static {k = 1; } ' – nhahtdh
@KennyTM Vâng, nếu tôi đã chạy nó theo cách giống như trong bài viết đó Bạn dán, tôi sẽ biết những gì đang xảy ra. – Hoto
@nhahtdh K sẽ được gán giá trị mặc định? Vậy tại sao mã này không comiple: class Test {công \t \t tĩnh {System.out.println (k); k = 2;} \t tĩnh int k; \t \t khoảng trống tĩnh công khai (Chuỗi [] args) { \t \t System.out.println (k); \t} } – Hoto