java 枚举 动态_Java动态修改Enum实例

这篇博客讨论了如何在Java中动态地修改枚举实例,尽管通常枚举的实例数量是固定的。通过反射和特殊技巧,可以创建新的枚举实例并更新涉及到枚举的switch语句。文章提供了示例代码,展示了如何创建和添加新的枚举实例,并处理可能遇到的问题,如数组越界异常。
摘要由CSDN通过智能技术生成

1347a268835097e00e199768a5d91cfa.png

众所周知,enum类型实例数量是固定的,甚至还被用来设计单例。但有时候仍然存在需要动态增加Enum实例的场景,这也并非一定是设计失败,也可能是增加灵活性的实际需求,比如一些web框架,再比如HanLPHanLP.svg?style=social&label=Fork HanLP.svg?style=social&label=Star HanLP.svg?style=social&label=Watch中的动态用户自定义词性。然而最大的障碍是switch语句生成的虚构类,本文参考Java Specialists第161期,提供一份可用的解决方案与实例代码。

一段有问题的代码

比如我们有一个enum类型:

public enum HumanState

{

HAPPY, SAD

}

我们是这样调用的:

public class Human

{

public void sing(HumanState state)

{

switch (state)

{

case HAPPY:

singHappySong();

break;

case SAD:

singDirge();

break;

default:

new IllegalStateException("Invalid State: " + state);

}

}

private void singHappySong()

{

System.out.println("When you're happy and you know it ...");

}

private void singDirge()

{

System.out.println("Don't cry for me Argentina, ...");

}

}

问题在哪里?如果你使用Intelij IDEA的话,你大概会得到一个友好的提示:

02c815036ab04fc2f20c1ab9445b56df.png

不过你可能会说,这个switch分支“永远”不会被触发,就算这句有问题也无伤大雅,甚至这个default分支根本没有存在的必要。

真的吗?

触发不可能的switch分支

Enum类也是类,既然是类,就能通过反射来创建实例,我们创建一个试试。

Constructor cstr = HumanState.class.getDeclaredConstructor(

String.class, int.class

);

ReflectionFactory reflection =

ReflectionFactory.getReflectionFactory();

HumanState e =

(HumanState) reflection.newConstructorAccessor(cstr).newInstance(new Object[]{"ANGRY", 3});

System.out.printf("%s = %d\n", e.toString(), e.ordinal());

Human human = new Human();

human.sing(e);

运行结果

结果出乎意料:

ANGRY = 3

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3

at com.hankcs.Human.sing(Human.java:21)

at com.hankcs.FireArrayIndexException.main(FireArrayIndexException.java:36)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:483)

at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

本来指望发生IllegalStateException,怎么出了一个ArrayIndexOutOfBoundsException?

探索问题

虽然我们成功地创建了一个新的Enum实例,但我们却数组越界了。stacktrace指出问题发生在:

switch (state)

这一句,我们不妨看看这一句编译后是什么样子的。借助IDEA的反编译插件,我们可以看到编译后反编译回来的代码:

public class Human {

public Human() {

}

public void sing(HumanState state) {

class Human$1 {

static {

try {

$SwitchMap$com$hankcs$HumanState[HumanState.HAPPY.ordinal()] = 1;

} catch (NoSuchFieldError var2) {

;

}

try {

$SwitchMap$com$hankcs$HumanState[HumanState.SAD.ordinal()] = 2;

} catch (NoSuchFieldError var1) {

;

}

}

}

switch(Human$1.$SwitchMap$com$hankcs$HumanState[state.ordinal()]) {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值