昨天策划找到我说,有两个功能的部分数据显示混乱,让我搞一下。我根据策划提供的流程走了一遍,嗯,没错,是个bug。没想到的是——之前写这部分逻辑的同志,在目标case逻辑结束的时候没写break,导致后面的case一并执行了。
还记得那是我在美好的大学时期 做C++课上测验的时候, 有这么一道题目(具体忘了,考察的是switch-case 知识点):
switch (1) {
case 1:
System.out.print("1");
case 2:
System.out.print("2");
break;
case 3:
System.out.print("3");
break;
default:
break;
}
结果输出__12__ 。 起初是很疑惑的的,为什么结果不是 1 。 仔细看了一下,在分支末尾没有写break, 所以case在匹配到目标之后会一直执行下去,直到遇到第一个break。当时只是记住了而已,没有深究下去。
现在再次遇见,一时兴起,遂研究:
使用javap -v XX.class之后,得到以下结果
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: iconst_1
1: tableswitch { // 1 to 3
1: 28 // 可以看到 我们的目标是要执行28 位置的命令
2: 36
3: 47
default: 58
}
28: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
31: ldc #22 // String 1
33: invokevirtual #24 // Method java/io/PrintStream.print:(Ljava/lang/String;)V ,
// 执行到这里目标的逻辑已经执行完毕了, print 已经打印完了。 **但是这里并没有跳转命令或者返回命令,那就继续往下走。**
36: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
39: ldc #30 // String 2
41: invokevirtual #24 // Method java/io/PrintStream.print:(Ljava/lang/String;)V,
// 走到这里之后,分支2 的逻辑已经执行完了,然后在后面 出现了goto 命令,跳转到 58 位置
44: goto 58
47: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #30 // String 2
52: invokevirtual #24 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
55: goto 58
58: return // 从方法中返回,返回值为void, 方法结束。
LineNumberTable:
line 15: 0
line 17: 28
line 20: 36
line 21: 44
line 23: 47
line 24: 55
line 30: 58
LocalVariableTable:
Start Length Slot Name Signature
0 59 0 args [Ljava/lang/String;
StackMapTable: number_of_entries = 4
frame_type = 28 /* same */
frame_type = 7 /* same */
frame_type = 10 /* same */
frame_type = 10 /* same */
}
附:javap生成的汇编语言指令表
switch-case 虽然很基础,但是使用的时候也要注意哦~