[英]Creating a final Java class array of enum constants with values( )
在Java枚舉類中,我想創建一個包含類的values()
的final static
數組。 當我沿着以下行執行此操作時,結果數組為null
。
public enum Name {
E1( stuff ), E2( stuff );
private static final Name[] values = Name.values();
private Name( stuff ) { more stuff; }
}
我也試過通過調用一個顯式的類setter方法來做到這一點,但是這給了一個java.lang.ExceptionInInitializerError
異常。
我理解這個問題是由一些淺的依賴引起的,因為前面代碼中的stuff
使用了其他類,這些類本身依賴於枚舉類。
是否有經過測試和驗證的技術來實現我的需求?
tl; dr:你想要做的事情是不可能的 - 枚舉類型的靜態字段在所有構造函數調用完成之后才會被初始化。
考慮這個例子:
public enum Name {
E1("hello"), E2("world");
private static final Name[] values = values();
private Name(String val) {
System.out.println("val = " + val);
dump();
}
protected void dump() {
System.out.println("this = " + this + ", values = " + values);
}
}
請注意,存在dump
方法的原因是嘗試從Name
的構造函數內部引用value
字段是編譯時錯誤( Java語言規范部分8.9.2 )。 有了這個測試工具:
public class Main {
public static void main(String... args) throws Exception {
System.out.println(Name.values());
}
}
我們得到
$ java Main
val = hello
this = E1, values = null
val = world
this = E2, values = null
[LName;@35960f05
使用javap
反編譯Name
類,我們看到以下內容:
private static final Name[] $VALUES;
public static Name[] values();
Code:
0: getstatic #1; //Field $VALUES:[LName;
3: invokevirtual #2; //Method "[LName;".clone:()Ljava/lang/Object;
6: checkcast #3; //class "[LName;"
9: areturn
編譯器創建一個包含值數組的私有字段$VALUES
,而values()
方法實現為{ return (Name[])$VALUES.clone() }
。 那么$VALUES
如何初始化?
static {};
Code:
0: new #4; //class Name
3: dup
4: ldc #19; //String E1
6: iconst_0
7: ldc #20; //String hello
9: invokespecial #21; //Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #22; //Field E1:LName;
15: new #4; //class Name
18: dup
19: ldc #23; //String E2
21: iconst_1
22: ldc #24; //String world
24: invokespecial #21; //Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #25; //Field E2:LName;
30: iconst_2
31: anewarray #4; //class Name
34: dup
35: iconst_0
36: getstatic #22; //Field E1:LName;
39: aastore
40: dup
41: iconst_1
42: getstatic #25; //Field E2:LName;
45: aastore
46: putstatic #1; //Field $VALUES:[LName;
49: invokestatic #26; //Method values:()[LName;
52: putstatic #18; //Field values:[LName;
55: return
}
我們在這里看到的是初始化基本上是這樣的:
// compiler-generated initialization code
E1 = new Name("hello");
E2 = new Name("world");
$VALUES = new Name[] {E1, E2};
// static initializer of the values field
values = Name.values();
所以在執行構造函數調用期間, values
字段將為null,而values()
方法將拋出NullPointerException(它將包含在ExceptionInInitializerError中)。
你能提供一個例子,因為它不應該是null。
public class Main {
public enum Name {
E1( ), E2( );
private static final Name[] VALUES = Name.values();
}
public static void main(String... args) {
System.out.println(Name.VALUES);
System.out.println(Arrays.asList(Name.VALUES));
}
}
版畫
[LMain$Name;@717e5fde
[E1, E2]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.