先看一段代码
public class Test { public static void main(String[] args) { int i = 7; switch (i) { case 1: System.out.println("1"); default: System.out.println("2"); case 3: System.out.println("3"); } } }
运行结果 2 3
通过javap -c Test.class查看字节码文件
Compiled from "Test.java" public class com.rsms.iot.service.Test { public com.rsms.iot.service.Test(); Code: 0: aload_0 //加载一个对象引用到操作数栈,在这里第一个变量是this,所以是将this引用压到操作数栈 1: invokespecial #1 // Method java/lang/Object."<init>":()V (构造方法、私有方法和父类中的方法) 4: return public static void main(java.lang.String[]); Code: 0: bipush 7 //将操作数7压到操作数栈中 2: istore_1 //将整形数字存储到本地变量中 3: iload_1 //i代表int,从局部变量数组中加载一个对象引用到操作数栈的栈顶 4: lookupswitch { // 2 1: 32 //为1匹配32行 3: 48 //同上 default: 40 //同上 } 32: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 35: ldc #3 // String 1 37: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 40: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 43: ldc #5 // String 2 45: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 48: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 51: ldc #6 // String 3 53: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 56: return }
先分析下字节码文件(局部变量表和操作数栈都属于当前栈帧,内存模型我在CSDN一篇博客中整理过:https://mp.csdn.net/postedit/68945933)
0:aload_0 会将this变量压到操作数栈中
0: bipush 初始化将变量推送至操作数栈栈顶
2: istore_1 将整形变量存储到本地局部变量表中位置为1的变量中
3: iload_1 将局部变量表中位置为1的变量的引用压到操作数栈中(个人理解是每次调用都会将变量的引用进行一次操作数栈的压栈操作),比如如下代码会有一次istore_1指令,两次iload_1指令。
int i = 7; System.out.println(i); System.out.println(i);
指令执行图示
从字节码文件可以看出,即使default在中间,编译后还是会在最后。所以匹配不到1、3时执行default,跳转到40行,40print执行之后,由于没有break语句,所以会顺序往下执行,会继续执行40行之后的所有语句。