switch
语句是一个很容易忽略的语法点,在表达式支持的类型上也犯过很多错,今天就来整理一下
switch (表达式){
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
关于break
在switch
语句的使用可以参考这篇博客https://cloud.tencent.com/developer/article/2342385
byte
、short
、int
、char
四种基本类型,以及其包装类型Enum
枚举类型虽然随着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方法来判断比较。