Đó là một quan niệm sai lầm phổ biến khi nghĩ rằng một khối tĩnh chỉ có quyền truy cập vào các trường tĩnh. Để làm điều này, tôi muốn trình bày đoạn mã dưới đây mà tôi thường sử dụng trong các dự án thực tế (được sao chép một phần từ câu trả lời khác trong ngữ cảnh hơi khác):
public enum Language {
ENGLISH("eng", "en", "en_GB", "en_US"),
GERMAN("de", "ge"),
CROATIAN("hr", "cro"),
RUSSIAN("ru"),
BELGIAN("be",";-)");
static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>();
static {
for (Language l:Language.values()) {
// ignoring the case by normalizing to uppercase
ALIAS_MAP.put(l.name().toUpperCase(),l);
for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l);
}
}
static public boolean has(String value) {
// ignoring the case by normalizing to uppercase
return ALIAS_MAP.containsKey(value.toUpper());
}
static public Language fromString(String value) {
if (value == null) throw new NullPointerException("alias null");
Language l = ALIAS_MAP.get(value);
if (l == null) throw new IllegalArgumentException("Not an alias: "+value);
return l;
}
private List<String> aliases;
private Language(String... aliases) {
this.aliases = Arrays.asList(aliases);
}
}
Ở đây, trình khởi tạo được sử dụng để duy trì một chỉ mục ( ALIAS_MAP
), để ánh xạ một tập các bí danh trở về kiểu enum ban đầu. Nó được dự định như một phần mở rộng cho phương thức valueOf tích hợp được cung cấp bởiEnum
chính nó .
Như bạn có thể thấy, trình khởi tạo tĩnh truy cập ngay cả private
trường aliases
. Điều quan trọng là phải hiểu rằng static
khối đã có quyền truy cập vào các Enum
trường hợp giá trị (ví dụ ENGLISH
). Điều này là do thứ tự khởi tạo và thực thi trong trường hợp các Enum
loại , giống như các static private
trường đã được khởi tạo với các thể hiện trước khi các static
khối được gọi:
- Các
Enum
hằng số là các trường tĩnh ẩn. Điều này đòi hỏi các khối xây dựng và khối đối tượng Enum và khởi tạo thể hiện cũng xảy ra trước tiên.
static
chặn và khởi tạo các trường tĩnh theo thứ tự xuất hiện.
Việc khởi tạo không theo thứ tự này (hàm tạo trước static
khối) rất quan trọng cần lưu ý. Nó cũng xảy ra khi chúng ta khởi tạo các trường tĩnh với các thể hiện tương tự như Singleton (đơn giản hóa được thực hiện):
public class Foo {
static { System.out.println("Static Block 1"); }
public static final Foo FOO = new Foo();
static { System.out.println("Static Block 2"); }
public Foo() { System.out.println("Constructor"); }
static public void main(String p[]) {
System.out.println("In Main");
new Foo();
}
}
Những gì chúng ta thấy là đầu ra sau đây:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
Rõ ràng là việc khởi tạo tĩnh thực sự có thể xảy ra trước hàm tạo và thậm chí sau:
Chỉ cần truy cập Foo trong phương thức chính, khiến lớp được tải và khởi tạo tĩnh bắt đầu. Nhưng như là một phần của khởi tạo tĩnh, chúng ta lại gọi các hàm tạo cho các trường tĩnh, sau đó nó tiếp tục khởi tạo tĩnh và hoàn thành hàm tạo được gọi từ bên trong phương thức chính. Tình huống khá phức tạp mà tôi hy vọng rằng trong mã hóa thông thường, chúng ta sẽ không phải đối phó.
Để biết thêm thông tin về điều này, hãy xem cuốn sách " Java hiệu quả ".
{...}
vsstatic {...}
. (trong trường hợp đó Jon Skeet chắc chắn đã trả lời câu hỏi của bạn tốt hơn)