为什么switch不支持long

switch 支持的类型

在 Java 语言规范里中,有说明 switch 支持的类型有:char、byte、short、int、Character、Byte、Short、Integer、String、enum。

为什么不支持 long ?

为什么只支持上面几种?int、String 都可以,为什么不支持 long ?

原因就是 switch 对应的 JVM 字节码 lookupswitch、tableswitch 指令只支持 int 类型

下面是 JVM 规范中的说明(https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.10):

The Java Virtual Machine's tableswitch and lookupswitch instructions operate only on int data. Because operations on byte, char, or short values are internally promoted to int, a switch whose expression evaluates to one of those types is compiled as though it evaluated to type int. If the chooseNear method had been written using type short, the same Java Virtual Machine instructions would have been generated as when using type int. Other numeric types must be narrowed to type int for use in a switch.

byte、char、short 类型在编译期默认提升为 int,并使用 int 类型的字节码指令。所以对这些类型使用 switch,其实跟 int 类型是一样的。

为什么可以支持 String?

switch 支持 String 其实就是语法糖。编译器会根据字符串的 hashCode 来处理。

例:

String a = "aa";
switch (a) {
  case "aa":
    System.out.println("111");
    break;
  case "AaAa":
    System.out.println("222");
    break;
  case "AaBB":
    System.out.println("333");
    break;
}

反编译后:

String var1 = "aa";
byte var3 = -1;
switch(var1.hashCode()) { // 第一个switch,根据hashCode计算第二个switch内的位置
  case 3104:
    if (var1.equals("aa")) {
      var3 = 0;
    }
    break;
  case 2031744:
    if (var1.equals("AaBB")) {
      var3 = 2;
    } else if (var1.equals("AaAa")) {
      var3 = 1;
    }
}

switch(var3) { // 第二个switch,执行原switch的逻辑
  case 0:
    System.out.println("111");
    break;
  case 1:
    System.out.println("222");
    break;
  case 2:
    System.out.println("333");
}

可以发现,会先根据 hashCode 找出原始 switch 内的位置,再执行原代码逻辑。

为什么用两个 switch ?

就是为了减少编译器的工作。

比如 switch 内有的 case 不写 break 等复杂情况,如果想直接根据 hashCode + equals 来只生成一个 switch,编译器就需要考虑各种情况。

所以目前编译器只做位置映射,第二部分直接按原 switch 来生成了。

关于 lookupswitch、tableswitch 可参考:你所不知道的Java之Switch

posted @ 2019-09-06 09:07  eycuii  阅读(2722)  评论(1编辑  收藏  举报