java enum 顺序_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 SomeEnum {

CONSTANT;

}

编译成类似于

final class SomeEnum extends Enum {

public static final SomeEnum CONSTANT = new SomeEnum();

}

Next, execute either the class variable initializers and static

initializers of the class, or the field initializers of the interface,

in textual order, as though they were a single block.

在下面的

final class SomeEnum extends Enum {

public static final SomeEnum CONSTANT = new SomeEnum();

public static final SomeEnum CONSTANT_2 = new SomeEnum();

}

首先将初始化CONSTANT,然后第二次初始化CONSTANT_2.

第四,如果当前线程正在初始化一个类,则可以正常进行.

If the Class object for C indicates that initialization is in progress

for C by the current thread, then this must be a recursive request for

initialization. Release LC and complete normally.

这一切如何融合在一起?

这个

ENUM.ANIMALS.CATS.GARFIELD.RIVAL

被评估为

CATS cat = ENUM.ANIMALS.CATS.GARFIELD;

DOGS rvial = cat.RIVAL;

首次访问GARFIELD会强制初始化枚举类型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尚未分配值.目前,它在堆栈中的位置较低.因此其值为空.因此,GIN.RIVALS获得对null的引用.所有DOGS的RIVAL都发生相同的情况.

当所有DOGS都初始化后,执行返回到

private static final CATS FELIX = new CATS(DOGS.AKAME);

其中DOGS.AKAME现在引用完全初始化的DOGS对象.这将分配给它的CATS#RIVAL字段.每个CATS都相同.换句话说,为所有CATS的RIVAL字段分配了DOGS参考,但没有相反的方式.

对语句重新排序只需确定首先枚举哪种枚举类型.

标签:enums,java

来源: https://codeday.me/bug/20191120/2046446.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值