switch可以进行跳转优化,java中对switch有两种处理方式,生成不同的jvm指令,一是tableswitch,一个是lookupswitch.
对于case的分支比较密集的情况,如
使用tableswitch,得到
从中可以看到tableswitch使用的跳转表。它这样查找,如果case值不在//0 to 14之间,直接执行default,如果在此范围之内,则取目标值-0这一项作为目标,比如switch(i),i为3,则跳转到3-0=3,使用数组中的第三项作为目标,也就是3: 98;直接去执行98行。
如果case中的值比较稀疏,则使用lookupswitch:
编译为
可以看到其中的
3: lookupswitch{ //4
3: 44;
20: 55;
50: 66;
100: 77;
default: 85 }
这个就要挨着查表确定跳转位置了。
对于case的分支比较密集的情况,如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public
class
Test {
public
static
void
main(String[] args) {
int
i =
3
;
switch
(i) {
case
0
:
System.out.println(
"0"
);
break
;
case
1
:
System.out.println(
"1"
);
break
;
case
3
:
System.out.println(
"3"
);
break
;
case
5
:
System.out.println(
"5"
);
break
;
case
10
:
System.out.println(
"10"
);
break
;
case
13
:
System.out.println(
"13"
);
break
;
case
14
:
System.out.println(
"14"
);
break
;
default
:
System.out.println(
"default"
);
break
;
}
}
}
|
使用tableswitch,得到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
public
static
void
main(java.lang.String[]);
Code:
0
: iconst_3
1
: istore_1
2
: iload_1
3
: tableswitch{
//0 to 14
0
:
76
;
1
:
87
;
2
:
153
;
3
:
98
;
4
:
153
;
5
:
109
;
6
:
153
;
7
:
153
;
8
:
153
;
9
:
153
;
10
:
120
;
11
:
153
;
12
:
153
;
13
:
131
;
14
:
142
;
default
:
153
}
76
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
79
: ldc #
3
;
//String 0
81
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
84
:
goto
161
87
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
90
: ldc #
5
;
//String 1
92
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
95
:
goto
161
98
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
101
: ldc #
6
;
//String 3
103
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
106
:
goto
161
109
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
112
: ldc #
7
;
//String 5
114
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
117
:
goto
161
120
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
123
: ldc #
8
;
//String 10
125
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
128
:
goto
161
131
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
134
: ldc #
9
;
//String 13
136
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
139
:
goto
161
142
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
145
: ldc #
10
;
//String 14
147
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
150
:
goto
161
153
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
156
: ldc #
11
;
//String default
158
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
161
:
return
}
|
从中可以看到tableswitch使用的跳转表。它这样查找,如果case值不在//0 to 14之间,直接执行default,如果在此范围之内,则取目标值-0这一项作为目标,比如switch(i),i为3,则跳转到3-0=3,使用数组中的第三项作为目标,也就是3: 98;直接去执行98行。
如果case中的值比较稀疏,则使用lookupswitch:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
Test2 {
public
static
void
main(String[] args) {
int
i =
3
;
switch
(i) {
case
3
:
System.out.println(
"3"
);
break
;
case
20
:
System.out.println(
"20"
);
break
;
case
50
:
System.out.println(
"50"
);
break
;
case
100
:
System.out.println(
"100"
);
break
;
}
}
}
|
编译为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
static
void
main(java.lang.String[]);
Code:
0
: iconst_3
1
: istore_1
2
: iload_1
3
: lookupswitch{
//4
3
:
44
;
20
:
55
;
50
:
66
;
100
:
77
;
default
:
85
}
44
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
47
: ldc #
3
;
//String 3
49
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
52
:
goto
85
55
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
58
: ldc #
5
;
//String 20
60
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
63
:
goto
85
66
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
69
: ldc #
6
;
//String 50
71
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
74
:
goto
85
77
: getstatic #
2
;
//Field java/lang/System.out:Ljava/io/PrintStream;
80
: ldc #
7
;
//String 100
82
: invokevirtual #
4
;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
85
:
return
|
可以看到其中的
3: lookupswitch{ //4
3: 44;
20: 55;
50: 66;
100: 77;
default: 85 }
这个就要挨着查表确定跳转位置了。