乐趣区

关于java:switch-是如何支持-String-的为什么不支持-long

作者: Jitwxs\
链接: https://jitwxs.cn/6f3eddff.html

咱们晓得 Java Switch 反对 byte、short、int 类型,在 JDK 1.5 时,反对了枚举类型,在 JDK 1.7 时,又反对了 String 类型。

那么它为什么就不能反对 long 类型呢,明明它跟 byte、short、int 一样都是数值型,它又是咋反对 String 类型的呢?

一、论断

不卖关子,先说论断:

switch 底层是应用 int 型 来进行判断的,即便是枚举、String 类型,最终也是转变成 int 型。因为 long 型示意范畴大于 int 型,因而不反对 long 类型。

上面具体介绍下各个类型是如何被转变成 int 类型的,应用的编译命令为 javac。

二、枚举类型是咋变成 int 类型的?

在没有试验之前,我想当然的认为它是不是依据枚举的 int 型字段来计算的(因为个别枚举都是一个 int 型,一个 string 型),然而转念一想,万一枚举没有 int 型字段呢,万一有多个 int 型字段呢,所以必定不是这样的,上面看试验吧。

定义两个枚举类,一个枚举类有一个 int 型属性,一个 string 型属性,另外一个枚举类只有一个 string 属性:

public enum SexEnum {MALE(1, "男"),  
    FEMALE(0, "女");  
  
    private int type;  
  
    private String name;  
  
    SexEnum(int type, String name) {  
        this.type = type;  
        this.name = name;  
    }  
}  
public enum Sex1Enum {MALE("男"),  
    FEMALE("女");  
    private String name;  
  
    Sex1Enum(String name) {this.name = name;}  
}  

而后编写一个测试类,并且让两个枚举 switch 的 FEMALE 和 MALE 对应的返回值不同:

public class SwitchTest {public int enumSwitch(SexEnum sex) {switch (sex) {  
            case MALE:  
                return 1;  
            case FEMALE:  
                return 2;  
            default:  
                return 3;  
        }  
    }  
  
    public int enum1Switch(Sex1Enum sex) {switch (sex) {  
            case FEMALE:  
                return 1;  
            case MALE:  
                return 2;  
            default:  
                return 3;  
        }  
    }  
}  

将这几个类反编译下:

// SexEnum.class  
public enum SexEnum {MALE(1, "鐢�"),  
   FEMALE(0, "濂�");  
   private int type;  
   private String name;  
   // $FF: synthetic field  
   private static final SexEnum[] $VALUES = new SexEnum[]{MALE, FEMALE};  
  
  
   private SexEnum(int var3, String var4) {  
      this.type = var3;  
      this.name = var4;  
   }  
  
}  
  
// Sex1Enum.class  
public enum Sex1Enum {MALE("鐢�"),  
   FEMALE("濂�");  
   private String name;  
   // $FF: synthetic field  
   private static final Sex1Enum[] $VALUES = new Sex1Enum[]{MALE, FEMALE};  
  
  
   private Sex1Enum(String var3) {this.name = var3;}  
  
}  

反编译这两个枚举类,发现其中多了一个 $VALUES 数组,外部蕴含了所有的枚举值。持续反编译测试类:

// SwitchTest$1.class  
import com.example.express.test.Sex1Enum;  
import com.example.express.test.SexEnum;  
  
// $FF: synthetic class  
class SwitchTest$1 {  
  
   // $FF: synthetic field  
   static final int[] $SwitchMap$com$example$express$test$SexEnum;  
   // $FF: synthetic field  
   static final int[] $SwitchMap$com$example$express$test$Sex1Enum = new int[Sex1Enum.values().length];  
  
  
   static {  
      try {$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.FEMALE.ordinal()] = 1;  
      } catch (NoSuchFieldError var4) {;}  
  
      try {$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.MALE.ordinal()] = 2;  
      } catch (NoSuchFieldError var3) {;}  
  
      $SwitchMap$com$example$express$test$SexEnum = new int[SexEnum.values().length];  
  
      try {$SwitchMap$com$example$express$test$SexEnum[SexEnum.MALE.ordinal()] = 1;  
      } catch (NoSuchFieldError var2) {;}  
  
      try {$SwitchMap$com$example$express$test$SexEnum[SexEnum.FEMALE.ordinal()] = 2;  
      } catch (NoSuchFieldError var1) {;}  
  
   }  
}  

首先生成了一个名为 SwitchTest$1.java 的链接类,外面定义了两个枚举数组,这两个数组元素增加的程序齐全和测试类中 switch 类调用的程序统一。

枚举元素在数组中的下标由 ordinal() 函数决定,该办法就是返回枚举元素在枚举类中的序号。

这里咱们其实就曾经晓得了,在 switch 语句中,是依据枚举元素在枚举中的序号来转变成 int 型的。最初再看下测试类的反编译后果验证下:

// SwitchTest.class  
import com.example.express.test.Sex1Enum;  
import com.example.express.test.SexEnum;  
import com.example.express.test.SwitchTest.1;  
  
public class SwitchTest {public int enumSwitch(SexEnum var1) {switch(1.$SwitchMap$com$example$express$test$SexEnum[var1.ordinal()]) {  
      case 1:  
         return 1;  
      case 2:  
         return 2;  
      default:  
         return 3;  
      }  
   }  
  
   public int enum1Switch(Sex1Enum var1) {switch(1.$SwitchMap$com$example$express$test$Sex1Enum[var1.ordinal()]) {  
      case 1:  
         return 1;  
      case 2:  
         return 2;  
      default:  
         return 3;  
      }  
   }  
}  

三、String 类型是咋变成 int 类型的?

首先咱们先晓得 char 类型是如何变成 int 类型的,很简略,是 ASCII 码,例如存在 switch 语句:

public int charSwitch(char c) {switch (c) {  
        case 'a':  
            return 1;  
        case 'b':  
            return 2;  
        default:  
            return Integer.MAX_VALUE;  
    }  
}  

反编译后果:

public int charSwitch(char var1) {switch(var1) {  
        case 97:  
            return 1;  
        case 98:  
            return 2;  
        default:  
            return Integer.MAX_VALUE;  
    }  
}  

那么对于 String 来说,利用的就是 hashCode() 函数了,然而 两个不同的字符串 hashCode() 是有可能相等的,这时候就得靠 equals() 函数了,例如存在 switch 语句:

public int stringSwitch(String ss) {switch (ss) {  
        case "ABCDEa123abc":  
            return 1;  
        case "ABCDFB123abc":  
            return 2;  
        case "helloWorld":  
            return 3;  
        default:  
            return Integer.MAX_VALUE;  
    }  
}  

其中字符串 ABCDEa123abc 和 ABCDFB123abc 的 hashCode 是相等的,反编译后果为:

public int stringSwitch(String var1) {  
   byte var3 = -1;  
   switch(var1.hashCode()) {  
       case -1554135584:  
          if(var1.equals("helloWorld")) {var3 = 2;}  
          break;  
       case 165374702:  
          if(var1.equals("ABCDFB123abc")) {var3 = 1;} else if(var1.equals("ABCDEa123abc")) {var3 = 0;}  
   }  
  
   switch(var3) {  
       case 0:  
          return 1;  
       case 1:  
          return 2;  
       case 2:  
          return 3;  
       default:  
          return Integer.MAX_VALUE;  
   }  
}  

能够看到它引入了局部变量 var3,对于 hashCode 相等状况通过 equals() 办法判断,最初再判断 var3 的值。

四、它们的包装类型反对吗?

这里以 Integer 类型为例,Character 和 Byte 同理,例如存在 switch 语句:

public int integerSwitch(Integer c) {switch (c) {  
        case 1:  
            return 1;  
        case 2:  
            return 2;  
    }  
    return -1;  
}  

反编译后果为:

public int integerSwitch(Integer var1) {switch(var1.intValue()) {  
        case 1:  
            return 1;  
        case 2:  
            return 2;  
        default:  
            return -1;  
    }  
}  

能够看到,是反对包装类型的,通过主动拆箱解决。

那万一包装类型是 NULL 咋办,首先咱们晓得 swtich 的 case 是不给加 null 的,编译都通不过,那如果传 null 呢?

答案是 NPE,毕竟理论还是包装类型的拆箱,天然就报空指针了。

另外,关注公众号 Java 技术栈,在后盾回复:面试,能够获取我整顿的 Java 系列面试题和答案,十分齐全。
近期热文举荐:

1.Java 15 正式公布,14 个新个性,刷新你的认知!!

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 我用 Java 8 写了一段逻辑,共事直呼看不懂,你试试看。。

4. 吊打 Tomcat,Undertow 性能很炸!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版