假设有这么一段 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 吧……