เป็นความเข้าใจผิดที่พบโดยทั่วไปว่าบล็อกคงมีเพียงการเข้าถึงฟิลด์คงที่ สำหรับสิ่งนี้ฉันต้องการแสดงโค้ดด้านล่างซึ่งฉันมักใช้ในโครงการในชีวิตจริง (คัดลอกบางส่วนจากคำตอบอื่นในบริบทที่แตกต่างกันเล็กน้อย):
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);
}
}
ที่นี่ initializer จะใช้ในการรักษาดัชนี ( ALIAS_MAP
) เพื่อแมปชุดของชื่อแทนกลับไปที่ประเภท Enum ดั้งเดิม มันมีวัตถุประสงค์เพื่อเป็นส่วนขยายไปยังวิธีการ valueOf ในตัวที่จัดทำโดยEnum
ตัวมันเอง
ในขณะที่คุณสามารถดู initializer คงเข้าถึงแม้ฟิลด์private
aliases
สิ่งสำคัญคือต้องเข้าใจว่าstatic
บล็อกนั้นมีการเข้าถึงEnum
อินสแตนซ์ของค่า (เช่นENGLISH
) นี่เป็นเพราะลำดับของการเริ่มต้นและการดำเนินการในกรณีที่เป็นEnum
ประเภทเช่นเดียวกับstatic private
เขตข้อมูลที่ได้รับการเริ่มต้นด้วยอินสแตนซ์ก่อนที่จะstatic
มีการเรียกบล็อก:
Enum
ค่าคงที่ซึ่งเป็นสาขาที่คงที่โดยปริยาย สิ่งนี้ต้องใช้คอนสตรัคเตอร์ Enum และอินสแตนซ์บล็อกและการเริ่มต้นอินสแตนซ์ให้เกิดขึ้นก่อนเช่นกัน
static
บล็อกและการเริ่มต้นของฟิลด์คงที่ในลำดับของการเกิดขึ้น
การกำหนดค่าเริ่มต้นที่static
ไม่เป็นไปตามคำสั่ง (ตัวสร้างก่อนบล็อก) เป็นสิ่งสำคัญที่ควรทราบ นอกจากนี้ยังเกิดขึ้นเมื่อเราเริ่มต้นเขตข้อมูลคงที่ด้วยอินสแตนซ์ที่คล้ายกับ Singleton (ทำให้เข้าใจง่าย):
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();
}
}
สิ่งที่เราเห็นคือผลลัพธ์ต่อไปนี้:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
ชัดเจนว่าการเริ่มต้นคงที่สามารถเกิดขึ้นจริงก่อนที่จะสร้างและแม้หลังจาก:
เพียงเข้าถึง Foo ในวิธีการหลักทำให้คลาสที่จะโหลดและการเริ่มต้นแบบคงที่เพื่อเริ่มต้น แต่เป็นส่วนหนึ่งของการเริ่มต้นแบบคงที่เราเรียกตัวสร้างอีกครั้งสำหรับเขตข้อมูลแบบคงที่หลังจากที่มันกลับมาเริ่มต้นแบบคงที่และดำเนินการก่อสร้างที่เรียกว่าจากภายในวิธีการหลัก ค่อนข้างซับซ้อนสถานการณ์ที่ฉันหวังว่าในการเขียนโปรแกรมปกติเราจะไม่ต้องจัดการกับ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ดูหนังสือ " Java ที่มีประสิทธิภาพ "
{...}
static {...}
(ในกรณีนี้ Jon Skeet ตอบคำถามของคุณได้ดีขึ้นอย่างแน่นอน)