[英]Creating a final Java class array of enum constants with values( )
Inside a Java enumerated class, I'd like to create a final static
array containing the values()
of the class. 在Java枚举类中,我想创建一个包含类的values()
的final static
数组。 When I do this along the following lines, the resulting array is null
. 当我沿着以下行执行此操作时,结果数组为null
。
public enum Name {
E1( stuff ), E2( stuff );
private static final Name[] values = Name.values();
private Name( stuff ) { more stuff; }
}
I've also tried doing this by calling an explicit class setter method, but this gave an java.lang.ExceptionInInitializerError
exception. 我也试过通过调用一个显式的类setter方法来做到这一点,但是这给了一个java.lang.ExceptionInInitializerError
异常。
I understand the problem is caused by some shallow dependencies as the stuff
in the previous code uses other classes, which themselves depend on the enumerated class. 我理解这个问题是由一些浅的依赖引起的,因为前面代码中的stuff
使用了其他类,这些类本身依赖于枚举类。
Is there a tested and proven technique to achieve what I need? 是否有经过测试和验证的技术来实现我的需求?
tl;dr: what you're trying to do isn't possible - static fields of an enum type don't get initialized until after all the constructor calls have completed. tl; dr:你想要做的事情是不可能的 - 枚举类型的静态字段在所有构造函数调用完成之后才会被初始化。
Consider this example: 考虑这个例子:
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);
}
}
Note that the reason for the existence of the dump
method is that it is a compile-time error ( Java Language Spec section 8.9.2 ) to try and reference the value
field from inside the constructor of Name
. 请注意,存在dump
方法的原因是尝试从Name
的构造函数内部引用value
字段是编译时错误( Java语言规范部分8.9.2 )。 With this test harness: 有了这个测试工具:
public class Main {
public static void main(String... args) throws Exception {
System.out.println(Name.values());
}
}
we get 我们得到
$ java Main
val = hello
this = E1, values = null
val = world
this = E2, values = null
[LName;@35960f05
Decompiling the Name
class with javap
we see the following: 使用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
The compiler creates a private field $VALUES
holding the value array, and the values()
method is implemented as { return (Name[])$VALUES.clone() }
. 编译器创建一个包含值数组的私有字段$VALUES
,而values()
方法实现为{ return (Name[])$VALUES.clone() }
。 So how does $VALUES
get initialized? 那么$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
}
What we see here is that the initialization essentially does: 我们在这里看到的是初始化基本上是这样的:
// 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();
so during the execution of the constructor calls, the values
field will be null and the values()
method will throw a NullPointerException (which will get wrapped in an ExceptionInInitializerError). 所以在执行构造函数调用期间, values
字段将为null,而values()
方法将抛出NullPointerException(它将包含在ExceptionInInitializerError中)。
Can you provide an example where this happens because it shouldn't be null. 你能提供一个例子,因为它不应该是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));
}
}
prints 版画
[LMain$Name;@717e5fde
[E1, E2]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.