Java 7 字符串开关反编译:意外指令

2022-09-04 02:41:55

我反编译了一个非常简单的类,它使用新的Java 7 String Switch功能。

课程:

public class StringSwitch {

    public static void main(String[] args) {

        final String color = "red";
        switch (color) {
            case "red":
                System.out.println("IS RED!");
                break;
            case "black":
                System.out.println("IS BLACK");
                break;
            case "blue":
                System.out.println("IS BLUE");
                break;
            case "green":
                System.out.println("IS GREEN");
                break;
        }

    }

}

对此类运行 Java 7 “javap”,生成一组有趣的指令(完整的反汇编代码可在此处找到):

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=2, locals=4, args_size=1
        ...
        12: lookupswitch  { // 4

                  112785: 56

                 3027034: 84

                93818879: 70

                98619139: 98
                 default: 109
            }
        56: aload_2       
        57: ldc           #2                  // String red
        ...       
       110: tableswitch   { // 0 to 3

                       0: 140

                       1: 151

                       2: 162

                       3: 173
                 default: 181
            }
       140: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
       143: ldc           #9                  // String IS RED!
       ...
       181: return

“LOOKUPSWITCH”是当开关大小写稀疏时使用的指令,可以替换 TABLESWITCH,即“switch”语句的默认指令。

那么,问题是,为什么我们看到一个“LOOKUPSWITCH”后面跟着一个“TABLESWITCH”?

谢谢卢西亚诺


答案 1

使用开关中的字符串查找正确的大小写语句是一个 2 步骤的过程。

  1. 计算开关字符串的哈希码,并在 case 语句中查找“哈希码匹配”,这是通过 LOOKUPSWITCH 完成的。请注意 LOOKUPSWITCH 下的大整数,这些是 case 语句中字符串的哈希码。
  2. 现在,2个字符串可以具有相同的哈希码,尽管不太可能。因此,实际的字符串比较仍然必须进行。因此,一旦哈希码匹配,开关字符串将与匹配的 case 语句中的字符串进行比较。LOOKUPSWITCH 和 TABLESWITCH 之间的指令正是这样做的。确认匹配后,将通过 TABLESWITCH 访问要为匹配的案例语句执行的代码。

另请注意,指定您使用的编译器 - javac 或 ECJ(Java 的 Eclipse 编译器)很有用。两个编译器可能会以不同的方式生成字节码。


答案 2