switch语句的深入解析 - 极悦
专注Java教育14年 全国咨询/投诉热线:444-1124-454
极悦LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 switch语句的深入解析

switch语句的深入解析

更新时间:2020-11-17 17:51:37 来源:极悦 浏览920次

switch语句是Java控制语句里面非常基础的知识,也是老生常谈的内容。switch语句的语法比较简单,相对也容易掌握。然而,大部分人却是知其然,不知其所以然。本文将深入去探索switch语句的用法。


首先我们看看switch 语法的基本格式:

switch (表达式) {

case 常量表达式或枚举常量:

语句;

break;

case 常量表达式或枚举常量:

语句;

break;

......

default: 语句;

break;

}

switch 匹配的表达式可以是:

byte、short、char、int类型及 这4种类型的包装类型;

枚举类型;

String 类型;

case 匹配的表达式可以是:

常量表达式;

枚举常量;

注意一点: case提供了switch表达式的入口地址,一旦switch表达式与某个case分支匹配,则从该分支的语句开始执行,一直执行下去,即其后的所有case分支的语句也会被执行,直到遇到break语句。


看个例子体会一下:

public static void main(String[] args) {

String s = "a";

switch (s) {

case "a": //a分支

System.out.println("匹配成功1");

case "b": //b分支

System.out.println("匹配成功2");

case "c": //c分支

System.out.println("匹配成功3");

break;

case "d": //d分支

System.out.println("匹配成功4");

break;

default:

break;

}

}

运行结果:

匹配成功1

匹配成功2

匹配成功3


switch成功匹配了a分支,但a、b分支都没有 break 语句,所以一直执行a分支后的所有语句,直到遇到c分支的break语句才终止。

接下来我们来看看编译器对 switch表达式的各种类型的处理:

尽管 switch 支持的类型扩充了几个,但其实在底层中,swtich 只能支持4种基本类型,其他几个类型是通过一些方式来间接处理的,下面便是讲解编译器对扩充类型的处理。


1、对包装类的处理

对包装类的处理是最简单的 —— 拆箱。看下面的例子,switch 比较的是包装类 Byte 。

Byte b = 2;

switch (b) {

case 1:

System.out.println("匹配成功");

break;

case 2:

System.out.println("匹配成功");

break;

}

用jad反编译一下这段代码,得到的代码如下:

Byte b = Byte.valueOf((byte)2);

switch(b.byteValue())

{

case 1: // '\001'

System.out.println("\u5339\u914D\u6210\u529F");

break;

case 2: // '\002'

System.out.println("\u5339\u914D\u6210\u529F");

break;

}

反编译的代码很简单,底层的switch比较的是Byte通过(拆箱)方法byteValue()得到的byte值。顺便说一下,这段反编译代码不仅揭开了 拆箱 的解析原理,也展示了 装箱 的解析原理(第一句代码);


2. 枚举类型

为了简单起见,直接采用JDK提供的枚举类型的线程状态类 Thread.state 类。

Thread.State state = Thread.State.RUNNABLE;

switch (state) {

case NEW:

System.out.println("线程处于创建状态");

break;

case RUNNABLE:

System.out.println("线程处于可运行状态");

break;

case TERMINATED:

System.out.println("线程结束");

break;

default:

break;

}

反编译代码:

Sex sex = Sex.MALE;

switch($SWITCH_TABLE$Test_2018_1_14$Sex()[sex.ordinal()])

{

case 1: // '\001'

System.out.println("sex:male");

break;

case 2: // '\002'

System.out.println("sex:female");

break;

}

从编译代码中发现,编译器对于枚举类型的处理,是通过创建一个辅助数组来处理,这个数组是通过一个$SWITCH_TABLE$java$lang$Thread$State() 方法创建的,数组是一个int[]类型数组,数组很简单,在每个枚举常量的序号所对应的数组下标位置的赋一个值,按序号大小赋值,从1开始递增。


3、 对String类型的处理

依旧是先看个例子,再查看这个例子反编译代码,了解编译器的是如何解析的。

public static void main(String[] args) {

String s = "China";

switch (s) {

case "America":

System.out.println("匹配到美国");

break;

case "China":

System.out.println("匹配到中国");

break;

case "Japan":

System.out.println("匹配到日本");

default:

break;

}

}

反编译得到的代码:

public static void main(String args[])

{

String s = "China";

String s1;

switch((s1 = s).hashCode())

{

default:

break;

case 65078583:

if(s1.equals("China"))

System.out.println("\u5339\u914D\u5230\u4E2D\u56FD");

break;

case 71341030:

if(s1.equals("Japan"))

System.out.println("\u5339\u914D\u5230\u65E5\u672C");

break;

case 775550446:

if(s1.equals("America"))

System.out.println("\u5339\u914D\u5230\u7F8E\u56FD");

break;

}

}


从反编译的代码可以看出,switch 的String变量、case 的String常量都变成对应的字符串的 hash 值。也就是说,switch仍然没有超出它的限制,只是通过使用 String对象的hash值来进行匹配比较,从而支持 String 类型。

通过上面的例子我们不难看出,底层的switch只能处理4个基本类型的值。其他三种类型需要通过其他方式间接处理,即转成基本类型来处理。对枚举类型的处理,是通过枚举常量的序号及一个数组。而对字符串String的处理,是通过 String 的hash值。本文基本上已经很全面的对switch语句的用法进行了介绍,这也是借鉴了本站的Java SE教程中的内容,教程中对其他的Java控制语句的讲解也很到位,感兴趣的小伙伴可以前去观看学习。


提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>