Java枚举属性根据访问顺序返回null
我正在用Java探索枚举,看看它们如何被滥用,并且遇到了无法解释的行为。考虑以下类别:
public class PROGRAM {public enum ENUM {;
public enum ANIMALS {;
public enum CATS {
FELIX(DOGS.AKAME),
GARFIELD(DOGS.WEED),
BUBSY(DOGS.GIN);
CATS(DOGS dog) {this.RIVAL = dog;}
public DOGS RIVAL;
}
public enum DOGS {
GIN(CATS.FELIX), WEED(CATS.BUBSY), AKAME(CATS.GARFIELD);
DOGS(CATS cat) {this.RIVAL = cat;}
public CATS RIVAL;
}
}
}
public static void main(String[] args) {
System.out.println(ENUM.ANIMALS.CATS.GARFIELD.RIVAL);
System.out.println(ENUM.ANIMALS.DOGS.GIN.RIVAL);
}
}
如预期的那样,主函数中的第一条语句将显示“ WEED”。第二个将打印“ null”。但是,如果您切换它们,即
System.out.println(ENUM.ANIMALS.DOGS.GIN.RIVAL); System.out.println(ENUM.ANIMALS.CATS.GARFIELD.RIVAL);
第一条语句将显示“ FELIX”,第二条语句将显示“ null”。有没有人可以解释这种现象?
作为参考,我正在运行Java(TM)SE运行时环境(内部版本1.8.0_05-b13)
回答:
这与枚举和类初始化有关。
首先,enum
只是class
具有恒定字段的幻想。也就是说,您声明的枚举常量实际上只是static
字段。所以
enum SomeEnum { CONSTANT;
}
编译成类似于
final class SomeEnum extends Enum<SomeEnum> { public static final SomeEnum CONSTANT = new SomeEnum();
}
其次,static
字段以从左到右的顺序初始化,它们出现在源代码中。
接下来,以文本顺序执行类的类变量初始化器和静态初始化器,或接口的字段初始化器,就好像它们是单个块一样。
在下面的
final class SomeEnum extends Enum<SomeEnum> { public static final SomeEnum CONSTANT = new SomeEnum();
public static final SomeEnum CONSTANT_2 = new SomeEnum();
}
CONSTANT
将首先被初始化,然后被初始化CONSTANT_2
。
第三,当您访问类型的常量之一(实际上只是一个字段)时,该enum
类型将被[初始化]
[3]static
。
第四,如果当前线程正在初始化一个类,则可以正常进行。
如果
Class
对象C
表示C
当前线程正在进行初始化,则这必须是对初始化的递归请求。释放LC
并正常完成。
这一切如何融合在一起?
这个
ENUM.ANIMALS.CATS.GARFIELD.RIVAL
被评估为
CATS cat = ENUM.ANIMALS.CATS.GARFIELD;DOGS rvial = cat.RIVAL;
首次访问将GARFIELD
强制enum
类型的初始化CATS
。这开始初始化中的枚举常量CATS
。编译后,这些看起来像
private static final CATS FELIX = new CATS(DOGS.AKAME);private static final CATS GARFIELD = new CATS(DOGS.WEED);
private static final CATS BUBSY = new CATS(DOGS.GIN);
这些按顺序初始化。所以FELIX
先去。作为其新实例创建表达式的一部分,它访问DOGS.AKAME
,而该类型DOGS
尚未初始化,因此Java开始对其进行初始化。该DOGS
枚举类型,编译,看起来像
private static final DOGS GIN = new DOGS(CATS.FELIX);private static final DOGS WEED = new DOGS(CATS.BUBSY);
private static final DOGS AKAME = new DOGS(CATS.GARFIELD);
因此,我们从开始GIN
。在其新的实例创建表达式中,它尝试访问CATS.FELIX
。CATS
当前正在初始化,因此我们继续。CATS.FELIX
尚未分配值。目前,它在堆栈中的位置较低。因此其值为null
。因此GIN.RIVALS
获得对的引用null
。同样的情况,给所有DOGS
“
RIVAL
。
DOGS
初始化所有后,执行返回
private static final CATS FELIX = new CATS(DOGS.AKAME);
其中,DOGS.AKAME
现指完全初始化DOGS
的对象。那被分配给它的CATS#RIVAL
领域。每个都相同CATS
。换句话说,所有的CATS
‘
RIVAL
字段都被分配了一个DOGS
引用,但是没有相反的方式。
对语句重新排序只是确定enum
首先要初始化的类型。
以上是 Java枚举属性根据访问顺序返回null 的全部内容, 来源链接: utcz.com/qa/405310.html