switch case 配合 enum 还会生成一个匿名内部类呢?

2020-04-05 14:27:48 +08:00
 amiwrong123
//: enumerated/TrafficLight.java
// Enums in switch statements.
import static net.mindview.util.Print.*;

// Define an enum type:
enum Signal { GREEN, YELLOW, RED, }

public class TrafficLight {
    Signal color = Signal.RED;
    public void change() {
        switch(color) {
            // Note that you don't have to say Signal.RED
            // in the case statement:
            case RED:    color = Signal.GREEN;
                break;
            case GREEN:  color = Signal.YELLOW;
                break;
            case YELLOW: color = Signal.RED;
                break;
        }
    }
    public String toString() {
        return "The traffic light is " + color;
    }
    public static void main(String[] args) {
        TrafficLight t = new TrafficLight();
        for(int i = 0; i < 7; i++) {
            print(t);
            t.change();
        }
    }
} 

这是一个来自 java 编程思想的代码,我发现 out 目录还生成了一个 TrafficLight$1.class,意思生成了一个匿名内部类呢,这是因为 switchcase 吗?

TrafficLight.class 部分汇编如下:

  public void change();
   Code:
      0: getstatic     #4                  // Field TrafficLight$1.$SwitchMap$Signal:[I  这里去得到匿名内部类的静态成员
      3: aload_0
      4: getfield      #3                  // Field color:LSignal;
      7: invokevirtual #5                  // Method Signal.ordinal:()I
     10: iaload
     11: tableswitch   { // 1 to 3
                    1: 36
                    2: 46
                    3: 56
              default: 63
         }

TrafficLight$1.class 部分汇编如下:

class TrafficLight$1 {
 static final int[] $SwitchMap$Signal;  静态成员是个 int 数组

 static {};
   Code:
      0: invokestatic  #1                  // Method Signal.values:()[LSignal;
      3: arraylength
      4: newarray       int
      6: putstatic     #2                  // Field $SwitchMap$Signal:[I  为啥这里只有一个 putstatic,之后又三个 getstatic Field $SwitchMap$Signal:[I 呀?
      9: getstatic     #2                  // Field $SwitchMap$Signal:[I
     12: getstatic     #3                  // Field Signal.RED:LSignal;
     15: invokevirtual #4                  // Method Signal.ordinal:()I
     18: iconst_1
     19: iastore
     20: goto          24
     23: astore_0
     24: getstatic     #2                  // Field $SwitchMap$Signal:[I
     27: getstatic     #6                  // Field Signal.GREEN:LSignal;
     30: invokevirtual #4                  // Method Signal.ordinal:()I
     33: iconst_2
     34: iastore
     35: goto          39
     38: astore_0
     39: getstatic     #2                  // Field $SwitchMap$Signal:[I
     42: getstatic     #7                  // Field Signal.YELLOW:LSignal;
     45: invokevirtual #4                  // Method Signal.ordinal:()I


2171 次点击
所在节点    Java
3 条回复
lanterboy
2020-04-05 15:26:46 +08:00
是的,这个内部类是用来存储枚举的映射表的,它记录了枚举和跳转符号的关系。实际上 case 的还是对应的数值,调用时会经过一次枚举对象到索引的转换
amiwrong123
2020-04-05 16:32:39 +08:00
@lanterboy
好吧,但是 java 汇编我看得有点迷。。
TrafficLight.class 部分汇编里,感觉没有那句 getstatic #4 // Field TrafficLight$1.$SwitchMap$Signal:[I 也一样啊。因为后面调用了 Signal 枚举实例的 ordinal 方法了就返回了一个 int 值了啊,感觉也没没用上那个匿名内部类的静态的 int 数组成员啊。
alamaya
2020-04-05 19:03:57 +08:00
@amiwrong123
你看漏了 iaload,这里是取了映射数组下标(枚举的 ordinal )的值进行入栈的,这么做是为了使用 tableswitch

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/659605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX