前言

一个小姐姐拿着一个switch的选择题来问我。

之所以这么笃定地回答这个问题,并不是我知道其中原理,而是之前在一个群里,有人问了同类型的问题,我瞥了一眼记住了答案,所以才依葫芦画瓢。

小姐姐接着问我为什么,我说少个break,但凡再问一句:为什么少个break结果就不一样,我就回答不出来了。所以,为了将尴尬扼杀于摇篮,还是研究一下break在switch的作用。

 

从字节码出发

按照惯例,先写demo表述问题。

 public static void main(String[] args) {int i = 0;switch (i) {case 0:System.out.println(0);case 1:System.out.println(1);case 2:System.out.println(2);}

运行代码,结果如下:

*明明只匹配了case 0,为什么1和2也执行了? 很费解!按照惯用套路,看看字节码能不能给个答案。

javac编译和javap查看:

「tableswitch」「lookupswitch」都用于switch条件跳转,前者用于case值连续,例如上面代码中的0、1、2;后者用于case值不连续。

从字节码可以看出:switch中的case条件和对应代码块是分开的。如上图,case为0时,跳转到标号28代码处;为1时跳转到标号35代码处;为2时跳转到标号43代码处;default则跳转到标号49代码处。

这不,答案就出来了,当case 0匹配了之后,直接跳转到标号28代码处开始执行,输出0,然后策马奔腾,一路小下坡,顺序执行完后面所有代码,直到标号49 return,方法完执行完成,程序结束。

如果按照正常的思维,是不是case 0匹配之后,跳到28,执行完28、31、32输出0之后,就应该直接跳走,直接执行49。那么,这个"跳走”用字节码应该怎么表示?

用return?那不行,因为return会结束方法,这样switch后代码也无法执行。那怎么办嘞....

 

关于goto

goto:无条件跳转,goto 1表示跳转到标号1的代码处。

再写代码样例,这次在代码中给每个case都加上break。

  public static void main(String[] args) {int i = 0;switch (i) {case 0:System.out.println(0);break;case 10:System.out.println(1);break;case 2:System.out.println(2);break;}System.out.println("Hello World");}

重新编译,再来看看字节码。

如图,与第一次的字节码相比,在标号35、45都有了goto指令。如果case 0匹配成功,则跳到标号28执行,执行完代码块对应的31、32指令之后,执行35的goto指令跳转到标号55,这样就跳出了switch作用范围,case 1和2也不会被执行。

等等,怎么少了一个goto,在标号55的上方应该还有一个goto才对!其实这就涉及到了编译器优化技术,最后一个goto也是跳转到标号55的指令,但没有goto下一步也一样顺序执行此行指令,所以这个goto被编译器视为无用代码进行了消除。

 

switch和if区别

先用if实现上面switch逻辑。

  public static void main(String[] args) {int i = 0;if (i == 0) {System.out.println(0);} else if (i == 1) {System.out.println(1);} else if (i == 2) {System.out.println(2);}}

编译成字节码:

「if_icmpne」用于比较两个int数。从字节码也可以看出if和switch的区别:if条件和代码块的字节码是顺序的,switch条件和代码块是分开的;if自动生成goto指令,switch只有加了break才生成goto指令。

 

结语

case中的break告诉前端编译器:「给每个case对应代码块的最后加上goto」。这样,执行完匹配上的代码之后,就可以略过后面的case代码块了。

果然,求(xiao)知(jie)欲(jie)才是学习新知识的动力。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

为什么switch里的case没有break不行相关推荐

  1. switch……case里的case能不能同时定义多个值呢?

    在C#环境里,switch--case里的case能不能同时定义多个值呢? 下面这样写行吗?    int aa = Convert.ToInt16(Request.QueryString[" ...

  2. switch中的case穿透现象,记得break

    一.switch基本语法格式 switch(int或者string类型的字面值或者变量){case int或者string类型的字面值或者变量 :{java语句;java语句;.....break;/ ...

  3. switch语句块里面的case的后面的参数有什么要求?

    switch语句块里面的case后面的参数只能是常量,并且类型只能是整型.字符型.枚举类型enum.JDK1.7及以上还可以是字符串String类型

  4. Java学习篇五——分支(选择)结构之switch语句及其中的break作用

    写在前面:本人是借助两本参考书自学的,其中部分例子和语句均是来自参考书.第一本:<Java 编程指南>,[美] Budi Kurniawan 著,闫斌 贺莲 译.第二本:<第一行代码 ...

  5. “else if”是否比“switch()case”更快? [重复]

    本文翻译自:Is "else if" faster than "switch() case"? [duplicate] Possible Duplicate: ...

  6. 运算符-if语句-switch语句-循环语句-continue/break语句

    一.java中的运算符         1.赋值运算符 =         2.算数运算符[+   -   *   /   %(求余)   ++(自动加1)    --(自动减1)]         ...

  7. switch中使用continue和break

    如果你在switch中使用continue,continue生效是对于while循环 如果你在switch中使用break,break生效是对于switch. 如果在switch外使用continue ...

  8. java switch 表达式_switch case语句错误:case表达式必须是常量表达式

    问题 我的switch-case语句昨天完美无缺.但是当我今天早些时候运行代码时,eclipse给了我一个错误,用红色突出显示case语句并说:case表达式必须是常量表达式,它是常量我不知道发生了什 ...

  9. switch语句和case语句的特性

    ** switch语句和case语句的特性 ** switch语句格式: switch(表达式) {case 常量值1:语句体1;break;case 常量值2:语句体2;break;...defau ...

最新文章

  1. 学习新对象字面量语法
  2. 数字技术对就业的影响分析
  3. 一个简单的 Python-kivy 小程序
  4. mme设备内部错误_防爆电气设备安装的三大误区 你中招了没?
  5. 小白的算法初识课堂(part3)--递归
  6. php-cgi cpu很高,php-cgi占用cpu资源过高的解决方法
  7. ARCore-Unity3d教程2 - 基本概念
  8. Gstreamer调用pulseaudio播放流程(十三)
  9. C++ begin( ) cbegin( ) end() cend()区别
  10. Cisco IP Phone 功能亮相(4)
  11. MySQL闪退以及服务中没有MySQL和MySQL 服务无法启动。系统出错。发生系统错误 1067。 进程意外终止。
  12. 英语入门学习笔记2:英语语法知识树
  13. EMLOG模板山河网站主题分享
  14. 技术团队分享改进总结
  15. 一些比较好用的域名信息查询网站
  16. 安装 xorg-macros
  17. 为什么西游记中要给孙悟空戴上紧箍儿?
  18. [不明所以]android 5.0 couldn't find libmsc.so
  19. 强!Java实现MSN Messenger聊天
  20. 超简单定制一个Notes库专门设置和存储用户头像

热门文章

  1. js符号输入不可用_JS 控制非法字符的输入代码
  2. django Sometimes request.session.session_key is None
  3. php图片中不显示文字内容,水印效果 只有图片,文字不显示
  4. ios html字符转义字符串,iOS HTML特殊字符转译
  5. 单片机c语言三种经典程序结构,单片机C语言程序的结构和设计精选.docx
  6. linux centos 7定时任务添加,CentOS 7 cron服务 定时任务使用方法
  7. mysql建立索引注意事项_索引的原理及索引建立的注意事项
  8. loadrunner之协议选择
  9. C++设计模式-Composite组合模式
  10. 渗透测试之Nmap命令(二)