Java 热更新 switch 可能会踩坑?
假设有这么一段 Java 代码在线上运行。
现象
enum TypeEnum {
A,
B,
C,
}
public static String getFromTypeEnum(TypeEnum e) {
switch (e) {
case A:
return "A";
case B:
return "A";
default:
return "";
}
上线后发现逻辑有误,那就修改然后 Arthas mc retransform 就可以了,对吧。
public static String getFromTypeEnum(TypeEnum e) {
switch (e) {
case A:
return "A";
case C:
return "C";
default:
return "";
}
}
为什么结果始终不对呢?
原因
因为 switch (enum) 不是直接对枚举做 switch,而是根据枚举到编号的映射表来做 if,即改写得到 $SwithcMap$TypeEnum。第一次编译完成后,$SwitchMap 内部的 1 对应 A,2 对应 B,按当前代码顺序依次编号。retransform 只能替换字节码,并不会触发类的编译,也无法修改类的字段,那么,修改后字节码 lookupswitch 内的标号还是 1 2,但是对应的枚举已经修改为 A 和 C。编号对不上,C 从老映射表取得为 0,那么逻辑自然也对不上。
确实是比较小众的坑,怎么办呢,多用 if 吧……