switch表达式中可以用哪些类型
switch
语句是一个很容易忽略的语法点,在表达式支持的类型上也犯过很多错,今天就来整理一下
switch语句基本定义:
switch (表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
break在switch语句中的作用
关于break
在switch
语句的使用可以参考这篇博客https://www.cnblogs.com/EthanWong/p/13190595.html
表达式的取值
表达式的取值类型
- 在JDK6及以前,表达式只能是一个常量表达式或枚举常量。所以表达式的取值可以是:
byte
、short
、int
、char
四种基本类型,以及其包装类型Enum
枚举类型
- 在JDK7以后新增支持String类型
编译器对表达式取值的处理
虽然随着JDK版本迭代,支持的新类型越来越多,但是在编译的字节码层次,switch
语句还是只能支持基本的四种类型。
-
基本类型的处理
int
数据类型int a = 2; switch (a) { case 1: System.out.println("first"); break; case 2: System.out.println("second"); break; case 3: System.out.println("second"); break; default: System.out.println("null"); break; }
反编译后的代码
byte byte0 = 2; switch (byte0) { case 1: // '\001' System.out.println("first"); break; case 2: // '\002' System.out.println("second"); break; case 3: // '\003' System.out.println("second"); break; default: System.out.println("null"); break; }
其实从这里就可以看出,正是因为
int
和byte
、char
、short
之间可以隐式转换。所以可以直接支持其对应的四种包装类型char
类型的处理char c = '2'; switch (c) { case '1': System.out.println("first"); break; case '2': System.out.println("second"); break; case '3': System.out.println("second"); break; default: System.out.println("null"); break; }
反编译后的代码:
byte byte0 = 50; switch (byte0) { case 49: // '1' System.out.println("first"); break; case 50: // '2' System.out.println("second"); break; case 51: // '3' System.out.println("second"); break; default: System.out.println("null"); break; }
从代码来看,底层是通过比较字符的ASCII码来进行判断的。
-
包装类型的处理
Integer I = 4; switch (I) { case 1: System.out.println("first"); break; case 2: System.out.println("second"); break; case 3: System.out.println("second"); break; default: System.out.println("null"); break; }
经过反编译后的代码是
Integer integer = Integer.valueOf(4); switch (integer.intValue()) { case 1: // '\001' System.out.println("first"); break; case 2: // '\002' System.out.println("second"); break; case 3: // '\003' System.out.println("second"); break; default: System.out.println("null"); break; }
从反编译的代码中可以看出,
Integer
装箱的时候自动调用Integer
的valueof(int)
方法,拆箱的时候是自动调用Integer
的intValue
方法。对应到其他包装类型和Integer也类似。 -
枚举类型的处理
public enum ColorEnum{ RED,GREEN,YELLOW; } public class EnumTest{ public static void main(String args[]){ ColorEnum color = ColorEnum.YELLOW; switch(color){ case RED: System.out.println("Stop"); break; case GREEN: System.out.println("Pass"); break; case YELLOW: System.out.println("Wait"); break; default: System.out.println("null"); break; } } }
反编译:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://kpdus.tripod.com/jad.html // Decompiler options: packimports(3) fieldsfirst ansi space // Source File Name: EnumTest.java import java.io.PrintStream; public class EnumTest { public EnumTest() { } public static void main(String args[]) { ColorEnum colorenum = ColorEnum.YELLOW; static class 1 { static final int $SwitchMap$ColorEnum[]; //自动生成int数组,通过编号来表示枚举 static { $SwitchMap$ColorEnum = new int[ColorEnum.values().length]; try { $SwitchMap$ColorEnum[ColorEnum.RED.ordinal()] = 1; } catch (NoSuchFieldError nosuchfielderror) { } try { $SwitchMap$ColorEnum[ColorEnum.GREEN.ordinal()] = 2; } catch (NoSuchFieldError nosuchfielderror1) { } try { $SwitchMap$ColorEnum[ColorEnum.YELLOW.ordinal()] = 3; } catch (NoSuchFieldError nosuchfielderror2) { } } } switch (1..SwitchMap.ColorEnum[colorenum.ordinal()]) { case 1: // '\001' System.out.println("Stop"); break; case 2: // '\002' System.out.println("Pass"); break; case 3: // '\003' System.out.println("Wait"); break; default: System.out.println("null"); break; } } }
从反编译的代码可以看出,底层通过创建
$SwitchMap$ColorEnum[]
的int
数组,并通过数组的编号来表示枚举。 -
String类型的处理
public class StringTest{ public static void main (String args[]){ String s = "RED"; switch(s){ case RED: System.out.println("红色"); break; case GREEN: System.out.println("绿色"); break; case YELLOW: System.out.println("黄色"); break; default: System.out.println("null"); break; } } }
反编译后:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://kpdus.tripod.com/jad.html // Decompiler options: packimports(3) fieldsfirst ansi space // Source File Name: StringTest.java import java.io.PrintStream; public class StringTest { public StringTest() { } public static void main(String args[]) { String s = "RED"; String s1 = s;//创建string对象 byte byte0 = -1; switch (s1.hashCode()) { case 81009: //string常量用hash值表示 if (s1.equals("RED")) //避免hash碰撞,用equals辅助判断 byte0 = 0; break; case 68081379: if (s1.equals("GREEN")) byte0 = 1; break; case -1680910220: if (s1.equals("YELLOW")) byte0 = 2; break; } switch (byte0) { case 0: // '\0' System.out.println("红色"); break; case 1: // '\001' System.out.println("绿色"); break; case 2: // '\002' System.out.println("黄色"); break; default: System.out.println("null"); break; } } }
从代码中可以看出,在对
String
类型的处理中,是通过对常量的hash值和equals方法来判断比较。