java基础(六) switch语句的深入解析
引言
switch 语句是非常的基础的知识,掌握起来也不难掌握,语法比较简单。但大部分人基本是知其然,不知其所以然。譬如 早期JDK只允许switch的表达式的值 int及int类型以下的基本类型,后期的JDK却允许匹配比较 字符串、枚举类型,这是怎么做到的呢?原理是什么?本文将深入去探索。
一、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开始递增。 其代码如下:
//int 数组
private static int $SWITCH_TABLE$java$lang$Thread$State[];
//创建数组的方法
static int[] $SWITCH_TABLE$java$lang$Thread$State()
{
$SWITCH_TABLE$java$lang$Thread$State;
if($SWITCH_TABLE$java$lang$Thread$State == null) goto _L2; else goto _L1
_L1:
return;
_L2:
JVM INSTR pop ;
int ai[] = new int[Thread.State.values().length];
try
{
ai[Thread.State.BLOCKED.ordinal()] = 3;
}
catch(NoSuchFieldError _ex) { }
try
{
ai[Thread.State.NEW.ordinal()] = 1;
}
catch(NoSuchFieldError _ex) { }
try
{
ai[Thread.State.RUNNABLE.ordinal()] = 2;
}
catch(NoSuchFieldError _ex) { }
try
{
ai[Thread.State.TERMINATED.ordinal()] = 6;
}
catch(NoSuchFieldError _ex) { }
try
{
ai[Thread.State.TIMED_WAITING.ordinal()] = 5;
}
catch(NoSuchFieldError _ex) { }
try
{
ai[Thread.State.WAITING.ordinal()] = 4;
}
catch(NoSuchFieldError _ex) { }
return $SWITCH_TABLE$java$lang$Thread$State = ai;
}
}
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 类型。
总结:
- 底层的switc只能处理4个基本类型的值。其他三种类型需要通过其他方式间接处理,即转成基本类型来处理。
- 编译器对包装类的处理是通过 拆箱。
- 对枚举类型的处理,是通过枚举常量的序号及一个数组。
- 对字符串String的处理,是通过 String 的hash值。
java基础(六) switch语句的深入解析的更多相关文章
- 【Java基础】switch语句实现根据数字输出对应星期
代码: import java.util.Scanner; /* * switch语句格式: * switch(表达式) { * case 值1: * 语句体1; * break; * case 值2 ...
- Java基础(1):Switch语句注意的5个地方
不得不说的几点小秘密: 1. switch 后面小括号中表达式的值必须是整型或字符型 2. case 后面的值可以是常量数值,如 1.2:也可以是一个常量表达式,如 2+2 :但不能是变量或带有变量的 ...
- Java中的switch语句后面的控制表达式的数据类型
Java中的switch语句后面的控制表达式的数据类型 1.byte 2.char 3.short 4.int 5.枚举类型 6.Java 7允许java.lang.String类型
- java基础2 判断语句:if ... else 语句和 switch 语句
一.if ... else 判断语句 1.if ... else 判断语句的格式 1.1.格式一 if(判断条件){ 执行不满足条件的语句 } 1.2.格式二 if(判断语句){ 满足条件的语句 }e ...
- Java基础之循环语句、条件语句、switch case 语句
Java 循环结构 - for, while 及 do...while 顺序结构的程序语句只能被执行一次.如果您想要同样的操作执行多次,,就需要使用循环结构. Java中有三种主要的循环结构: whi ...
- java基础-控制流程语句
一 前言 周末睡觉好舒服,都不想动了,就想睡睡,晒晒太阳,作者劳碌命还是过来写文章了.基础系列文章已经已经出到控制流程,感觉也挺快的,我很自信全网没都多少系列文章能有我这基础系列写的这么好,易于初学者 ...
- java基础3 循环语句:While 循环语句、do while 循环语句、 for 循环语句 和 break、continue关键字
一.While循环语句 1.格式 while(条件表达式){ 执行语句: } 2.要点 1,先判断后执行 2,循环次数不定 3,避免死循环 3.举例 题目1:输出0-100之间的所有数 class D ...
- JavaSE入门学习7:Java基础语法之语句(下)
继续接着Java基础语法来:JavaSE入门学习5:Java基础语法(一)和JavaSE入门学习6:Java基础语法(二). 语句 Java经常使用的3种循环:while.do...while,for ...
- Java基础之开关语句详解
switch 语句是单条件多分支的开关语句,它的一般格式定义如下(其中break语句是可选的): switch(表达式) { case 常量值: 若干个语句 break; case 常量值: 若干个 ...
随机推荐
- Java学习笔记【持续更新】
一个简单的java程序如下: class Sakura { public static void main(String[] arges) { system.out.println("Hel ...
- ProjectEuler 做题记录
退役选手打发时间的PE计划 挂在这里主要是dalao们看到有什么想交流的东西可以私聊哦(站内信或邮箱吧)~~当然现在高三也不怎么能上网. 2017/8/11 595 :第一题QAQ 2017/8/1 ...
- bzoj:2595: [Wc2008]游览计划
Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数 ...
- BZOJ2001: [Hnoi2010]City 城市建设
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2001 cdq分治+重建图. 可以保留当前一定会被选的非修改边然后把点缩起来.这样的话每次点数至 ...
- Linux 文件操作命令-Linux基础环境命令学习笔记
1.文件目录操作 1)路径识别 a.绝对路径,以根目录开始 b.相对路径,以当前目录开始,不需从根目录开始写起 2)命令 man ls 查看ls命令帮助 cd /var/log 切换进入log目录(. ...
- 教你理解微信小程序的生命周期和运行原理
转自:http://blog.csdn.net/tsr106/article/details/53052879 写微信小程序,他的生命周期不能不知道,不知道小程序就会出现各种bug而无法解决.小助君 ...
- 自制ZigBee协议分析仪
关键词 ZigBee Sniffer 协议 分析仪 自制 CC2530 CC2531 在开发ZigBee / Bluetooth的过程,难免会要用到Sniffer工具,Packet Sni ...
- 全国银行列表json格式
var list=[ { value:'CDB', text:'国家开发银行' }, { value:'ICBC', text:'中国工商银行' }, { value:'ABC', text:'中国农 ...
- Node.js系列-http
前言: 最近一直忙着公司项目的事,战友们的留言也没空回复,博客也有段时间没有更新了,年底了就是一个的忙啊~~~(ps:同感的也给个赞吧) 现在前端的就是一直地更新一直有新的东西出来,什么ES2015, ...
- java中类的加载过程和对象的创建过程
1.类加载过程 首先,jvm在执行时,遇到一个新的类,会先去内存的方法区中去寻找该类的.class文件,如果找到了就直接运行,如果没有找到,则会去硬盘中去寻找该类的.class文件,并将该类文件加载到 ...