2012-11-25 72 views
7

thể trùng lặp:
Java static class initialization
in what order are static blocks and static variables in a class executed?Trình tự khởi tạo biến tĩnh, Java

Khi tôi chạy mã này câu trả lời là 1, tôi nghĩ nó sẽ là 2. gì là thứ tự khởi tạo và giá trị k trong mỗi bước?

public class Test { 

static {k = 2;} 
static int k = 1; 

public static void main(String[] args) { 
    System.out.println(k); 
} 
} 

Sửa 1: Là một theo dõi để "k được thiết lập để mặc định giá trị" thì tại sao mã tiếp theo này không biên dịch? Có lỗi "Không thể tham chiếu một trường trước khi được xác định".

public class Test { 

static {System.out.println(k);} 
static int k=1; 

public static void main(String[] args) { 
    System.out.println(k); 
} 
} 

Chỉnh sửa 2: Đối với một số unknow với tôi lý do nó^hoạt động khi thay vì "k" nó "Test.k".

Cảm ơn tất cả các câu trả lời. điều này sẽ sufice: D

+1

Đầ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

+0

@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

+0

@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

Trả lời

7

Chúng được thực thi theo thứ tự bạn viết chúng. Nếu mã là:

public class Test { 

    static int k = 1; 
    static {k = 2;} 

    public static void main(String[] args) { 
     System.out.println(k); 
    } 

} 

sau đó đầu ra trở nên 2.

Trình tự khởi tạo là: ..the class variable initializers and static initializers of the class..., in textual order, as though they were a single block.

Và các giá trị (đối với mã của bạn) là: k = 0 (mặc định), sau đó nó được thiết lập để 2, sau đó nó được thiết lập trở lại 1.

Bạn có thể kiểm tra xem nó thực sự thiết lập để 2 bằng cách chạy đoạn mã sau:

private static class Test { 

    static { 
     System.out.println(Test.k); 
     k = 2; 
     System.out.println(Test.k); 
     } 
    static int k = 1; 

    public static void main(String[] args) { 
     System.out.println(k); 
    } 
} 
+0

Đó không phải điều tôi muốn nói trong câu hỏi của tôi. Tôi muốn thứ tự khởi tạo và giá trị của k trong mỗi bước. – Hoto

+0

Ok, tôi đã thêm một lời giải thích chi tiết hơn. – tibtof

+0

Vâng ... nhưng bây giờ có một chút hỗn loạn trong Câu trả lời của bạn xD – Hoto

3

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ớplĩ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 str2stat1. Để 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.

+0

@EJP: Lưu ý rằng 2 điều kiện 1) ** biến lớp ** final và 2) initializer là hằng số biên dịch được thực hiện trong bước 6. Không có mâu thuẫn ở đây. Bạn thậm chí có thể kiểm tra các chương trình trên ideone. – nhahtdh

Các vấn đề liên quan