版本:jdk11,其他选项默认
1. switch基本语法
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的case语句 default : //可选 //语句 }
switch case 语句有如下规则:
- switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
- switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
- case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
- 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
- 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
- switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。
2. case自动类型转换
byte
、short
、char
会自动转换成int类型,然后进行比较;String
类型会调用hashcode()
方法,用int
类型返回值进行比较,然后使用equals()
进行进一步判断;enum
类型,会调用对象的ordinal()
方法,返回其对应的int
类型下标;
所有的case最终都会被转换成int类型,然后进行编译。
3. case匹配方式 lookupswitch & tableswitch
tableswitch:带有标签的表格。
lookupswitch:带有key索引和标签的表格。
当case比较紧凑时且数值接近0时,通常使用tableswitch
,直接使用下标进行索引,例如代码下文代码示例中的chooseNear()
方法,可以看到多出了几个选项,指向了default
选项L4
。效率为O(1)。
当case比较分散时且数值与0距离较远,通常使用lookupswitch
,其中的数值进行了排序,采用二分法进行查找,效率为O(log n)。
4. 代码示例
代码:
public class SmallIntDemo { public static void main(String[] args) { System.out.println(chooseFar(1)); System.out.println(chooseFar(1)); System.out.println(charNear('a')); System.out.println(stringMethod("hello")); System.out.println(enumMethod(CharEnum.a)); } enum CharEnum { a, b, c } static int chooseNear(int i) { switch (i) { case 0: return 0; case -1: return 0; case 1: return 1; case 2: return 2; case 8: return 8; default: return -1; } } static int chooseFar(int i) { switch (i) { case -100: return -1; case 0: return 0; case 100: return 1; default: return -1; } } static int charNear(char c) { switch (c) { case 'a': return 0; case 'b': return 0; case 'c': return 1; default: return -1; } } static int stringMethod(String str) { switch (str) { case "ok": return 0; case "fine": return 0; case "hello": return 1; default: return -1; } } static char enumMethod(CharEnum ce) { switch (ce) { case a: return 'a'; case b: return 'b'; case c: return 'c'; default: return ' '; } } }
编译结果:
// access flags 0x8 static chooseNear(I)I L0 LINENUMBER 30 L0 ILOAD 0 TABLESWITCH -1: L1 0: L2 1: L3 2: L4 3: L5 4: L5 5: L5 6: L5 7: L5 8: L6 default: L5 L2 LINENUMBER 32 L2 FRAME SAME ICONST_0 IRETURN L1 LINENUMBER 34 L1 FRAME SAME ICONST_0 IRETURN L3 LINENUMBER 36 L3 FRAME SAME ICONST_1 IRETURN L4 LINENUMBER 38 L4 FRAME SAME ICONST_2 IRETURN L6 LINENUMBER 40 L6 FRAME SAME BIPUSH 8 IRETURN L5 LINENUMBER 42 L5 FRAME SAME ICONST_M1 IRETURN L7 LOCALVARIABLE i I L0 L7 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x8 static chooseFar(I)I L0 LINENUMBER 47 L0 ILOAD 0 LOOKUPSWITCH -100: L1 0: L2 100: L3 default: L4 L1 LINENUMBER 49 L1 FRAME SAME ICONST_M1 IRETURN L2 LINENUMBER 51 L2 FRAME SAME ICONST_0 IRETURN L3 LINENUMBER 53 L3 FRAME SAME ICONST_1 IRETURN L4 LINENUMBER 55 L4 FRAME SAME ICONST_M1 IRETURN L5 LOCALVARIABLE i I L0 L5 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x8 static charNear(C)I L0 LINENUMBER 60 L0 ILOAD 0 TABLESWITCH 97: L1 98: L2 99: L3 default: L4 L1 LINENUMBER 62 L1 FRAME SAME ICONST_0 IRETURN L2 LINENUMBER 64 L2 FRAME SAME ICONST_0 IRETURN L3 LINENUMBER 66 L3 FRAME SAME ICONST_1 IRETURN L4 LINENUMBER 68 L4 FRAME SAME ICONST_M1 IRETURN L5 LOCALVARIABLE c C L0 L5 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x8 static stringMethod(Ljava/lang/String;)I L0 LINENUMBER 73 L0 ALOAD 0 ASTORE 1 ICONST_M1 ISTORE 2 ALOAD 1 INVOKEVIRTUAL java/lang/String.hashCode ()I LOOKUPSWITCH 3548: L1 3143098: L2 99162322: L3 default: L4 L1 FRAME APPEND [java/lang/String I] ALOAD 1 LDC "ok" INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z IFEQ L4 ICONST_0 ISTORE 2 GOTO L4 L2 FRAME SAME ALOAD 1 LDC "fine" INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z IFEQ L4 ICONST_1 ISTORE 2 GOTO L4 L3 FRAME SAME ALOAD 1 LDC "hello" INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z IFEQ L4 ICONST_2 ISTORE 2 L4 FRAME SAME ILOAD 2 TABLESWITCH 0: L5 1: L6 2: L7 default: L8 L5 LINENUMBER 75 L5 FRAME SAME ICONST_0 IRETURN L6 LINENUMBER 77 L6 FRAME SAME ICONST_1 IRETURN L7 LINENUMBER 79 L7 FRAME SAME ICONST_2 IRETURN L8 LINENUMBER 81 L8 FRAME SAME ICONST_M1 IRETURN L9 LOCALVARIABLE str Ljava/lang/String; L0 L9 0 MAXSTACK = 2 MAXLOCALS = 3 // access flags 0x8 static enumMethod(Lswitch_case/SmallIntDemo$CharEnum;)C L0 LINENUMBER 86 L0 GETSTATIC switch_case/SmallIntDemo$1.$SwitchMap$switch_case$SmallIntDemo$CharEnum : [I ALOAD 0 INVOKEVIRTUAL switch_case/SmallIntDemo$CharEnum.ordinal ()I IALOAD TABLESWITCH 1: L1 2: L2 3: L3 default: L4 L1 LINENUMBER 88 L1 FRAME SAME BIPUSH 97 IRETURN L2 LINENUMBER 90 L2 FRAME SAME BIPUSH 98 IRETURN L3 LINENUMBER 92 L3 FRAME SAME BIPUSH 99 IRETURN L4 LINENUMBER 94 L4 FRAME SAME BIPUSH 32 IRETURN L5 LOCALVARIABLE ce Lswitch_case/SmallIntDemo$CharEnum; L0 L5 0 MAXSTACK = 2 MAXLOCALS = 1 }
4. 参考文档
[2] Chapter 3. Compiling for the Java Virtual Machine
[3] stackoverflow: Difference between JVM's LookupSwitch and TableSwitch?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现