switch-case的字节码指令:
Java代码如下:
public class HelloWorld{
public int testSwitchCase(int a) {
int b = -23;
switch(a){
case 5:
System.out.println(5);
b = 1;
case 2:
System.out.println(2);
b = 2;
break;
case 1:
System.out.println(1);
b = 5;
case 6:
System.out.println(6);
b = 6;
default:
System.out.println("default");
b = 0;
}
return b;
}
public int testSwitchCase02(int a) {
switch(a){
case 100:
return 1;
case 2000:
return 2;
case 1:
return 5;
case 20:
return 6;
default:
return 0;
}
}
}
字节码指令如下:
$ javap -v HelloWorld.class
Classfile /D:/ideaproject/jvm/HelloWorld.class
Last modified 2019-6-24; size 883 bytes
MD5 checksum 0d1346a9766d2495fdad312ece7fbfc6
Compiled from "HelloWorld.java"
public class HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#24 // java/lang/Object."<init>":()V
#2 = Fieldref #25.#26 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #27.#28 // java/io/PrintStream.println:(I)V
#4 = String #29 // default
#5 = Methodref #27.#30 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Class #31 // HelloWorld
#7 = Class #32 // java/lang/Object
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 LocalVariableTable
#13 = Utf8 this
#14 = Utf8 LHelloWorld;
#15 = Utf8 testSwitchCase
#16 = Utf8 (I)I
#17 = Utf8 a
#18 = Utf8 I
#19 = Utf8 b
#20 = Utf8 StackMapTable
#21 = Utf8 testSwitchCase02
#22 = Utf8 SourceFile
#23 = Utf8 HelloWorld.java
#24 = NameAndType #8:#9 // "<init>":()V
#25 = Class #33 // java/lang/System
#26 = NameAndType #34:#35 // out:Ljava/io/PrintStream;
#27 = Class #36 // java/io/PrintStream
#28 = NameAndType #37:#38 // println:(I)V
#29 = Utf8 default
#30 = NameAndType #37:#39 // println:(Ljava/lang/String;)V
#31 = Utf8 HelloWorld
#32 = Utf8 java/lang/Object
#33 = Utf8 java/lang/System
#34 = Utf8 out
#35 = Utf8 Ljava/io/PrintStream;
#36 = Utf8 java/io/PrintStream
#37 = Utf8 println
#38 = Utf8 (I)V
#39 = Utf8 (Ljava/lang/String;)V
{
public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LHelloWorld;
public int testSwitchCase(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: bipush -23
2: istore_2
3: iload_1
4: tableswitch { // 1 to 6
1: 65
2: 53
3: 85
4: 85
5: 44
6: 74
default: 85
}
44: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
47: iconst_5
48: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
51: iconst_1
52: istore_2
53: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
56: iconst_2
57: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
60: iconst_2
61: istore_2
62: goto 95
65: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
68: iconst_1
69: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
72: iconst_5
73: istore_2
74: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
77: bipush 6
79: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
82: bipush 6
84: istore_2
85: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
88: ldc #4 // String default
90: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
93: iconst_0
94: istore_2
95: iload_2
96: ireturn
LineNumberTable:
line 4: 0
line 5: 3
line 7: 44
line 8: 51
line 10: 53
line 11: 60
line 12: 62
line 14: 65
line 15: 72
line 17: 74
line 18: 82
line 20: 85
line 21: 93
line 23: 95
LocalVariableTable:
Start Length Slot Name Signature
0 97 0 this LHelloWorld;
0 97 1 a I
3 94 2 b I
StackMapTable: number_of_entries = 6
frame_type = 252 /* append */
offset_delta = 44
locals = [ int ]
frame_type = 8 /* same */
frame_type = 11 /* same */
frame_type = 8 /* same */
frame_type = 10 /* same */
frame_type = 9 /* same */
public int testSwitchCase02(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: lookupswitch { // 4
1: 48
20: 50
100: 44
2000: 46
default: 53
}
44: iconst_1
45: ireturn
46: iconst_2
47: ireturn
48: iconst_5
49: ireturn
50: bipush 6
52: ireturn
53: iconst_0
54: ireturn
LineNumberTable:
line 28: 0
line 30: 44
line 32: 46
line 34: 48
line 36: 50
line 38: 53
LocalVariableTable:
Start Length Slot Name Signature
0 55 0 this LHelloWorld;
0 55 1 a I
StackMapTable: number_of_entries = 5
frame_type = 44 /* same */
frame_type = 1 /* same */
frame_type = 1 /* same */
frame_type = 1 /* same */
frame_type = 2 /* same */
}
SourceFile: "HelloWorld.java"
结论是:switch-case 语句 在 case 比较稀疏的情况下,编译器会使用 lookupswitch 指令来实现,反之,编译器会使用 tableswitch 来实现
枚举复习:
/**
* enum 对象的常用方法介绍:
* 1. int compareTo(E o) 比较此枚举与指定对象的顺序。
* 2. Class<E> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
* 3. String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
* 4. int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
* 5. String toString() 返回枚举常量的名称,它包含在声明中。
* 6. static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。
* @author zishi.ghq
*
*/
public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
//这段代码实际上调用了7次 Enum(String name, int ordinal):
// new Enum<EnumTest>("MON",0);
public static void main(String[] args) {
EnumTest[] values = EnumTest.values();
for (EnumTest enumTest : values) {
System.out.println(enumTest.name());
System.out.println(enumTest.ordinal());
}
System.out.println("---------------------------------");
EnumTest test = EnumTest.MON;
switch (test) {
case MON:
System.out.println("星期一");
break;
default:
System.out.println("不是星期一");
break;
}
System.out.println("---------------------------------");
System.out.println(test.compareTo(FRI));
//getDeclaringClass()
System.out.println(test.getDeclaringClass().getName());//jvm.EnumTest
//toString()
System.out.println(test.toString());//MON
//ordinal(), 返回值是从 0 开始
System.out.println(test.ordinal());
}
}
枚举
public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
汇编结果:
$ javap -v EnumTest.class
Classfile /D:/ideaproject/jvm/EnumTest.class
Last modified 2019-6-24; size 1089 bytes
MD5 checksum 43371fe799ea9f40ce42b722a4810a53
Compiled from "EnumTest.java"
public final class EnumTest extends java.lang.Enum<EnumTest>
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
#1 = Fieldref #4.#51 // EnumTest.$VALUES:[LEnumTest;
#2 = Methodref #52.#53 // "[LEnumTest;".clone:()Ljava/lang/Object;
#3 = Class #32 // "[LEnumTest;"
#4 = Class #54 // EnumTest
#5 = Methodref #22.#55 // java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
#6 = Methodref #22.#56 // java/lang/Enum."<init>":(Ljava/lang/String;I)V
#7 = String #23 // MON
#8 = Methodref #4.#56 // EnumTest."<init>":(Ljava/lang/String;I)V
#9 = Fieldref #4.#57 // EnumTest.MON:LEnumTest;
#10 = String #25 // TUE
#11 = Fieldref #4.#58 // EnumTest.TUE:LEnumTest;
#12 = String #26 // WED
#13 = Fieldref #4.#59 // EnumTest.WED:LEnumTest;
#14 = String #27 // THU
#15 = Fieldref #4.#60 // EnumTest.THU:LEnumTest;
#16 = String #28 // FRI
#17 = Fieldref #4.#61 // EnumTest.FRI:LEnumTest;
#18 = String #29 // SAT
#19 = Fieldref #4.#62 // EnumTest.SAT:LEnumTest;
#20 = String #30 // SUN
#21 = Fieldref #4.#63 // EnumTest.SUN:LEnumTest;
#22 = Class #64 // java/lang/Enum
#23 = Utf8 MON
#24 = Utf8 LEnumTest;
#25 = Utf8 TUE
#26 = Utf8 WED
#27 = Utf8 THU
#28 = Utf8 FRI
#29 = Utf8 SAT
#30 = Utf8 SUN
#31 = Utf8 $VALUES
#32 = Utf8 [LEnumTest;
#33 = Utf8 values
#34 = Utf8 ()[LEnumTest;
#35 = Utf8 Code
#36 = Utf8 LineNumberTable
#37 = Utf8 valueOf
#38 = Utf8 (Ljava/lang/String;)LEnumTest;
#39 = Utf8 LocalVariableTable
#40 = Utf8 name
#41 = Utf8 Ljava/lang/String;
#42 = Utf8 <init>
#43 = Utf8 (Ljava/lang/String;I)V
#44 = Utf8 this
#45 = Utf8 Signature
#46 = Utf8 ()V
#47 = Utf8 <clinit>
#48 = Utf8 Ljava/lang/Enum<LEnumTest;>;
#49 = Utf8 SourceFile
#50 = Utf8 EnumTest.java
#51 = NameAndType #31:#32 // $VALUES:[LEnumTest;
#52 = Class #32 // "[LEnumTest;"
#53 = NameAndType #65:#66 // clone:()Ljava/lang/Object;
#54 = Utf8 EnumTest
#55 = NameAndType #37:#67 // valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
#56 = NameAndType #42:#43 // "<init>":(Ljava/lang/String;I)V
#57 = NameAndType #23:#24 // MON:LEnumTest;
#58 = NameAndType #25:#24 // TUE:LEnumTest;
#59 = NameAndType #26:#24 // WED:LEnumTest;
#60 = NameAndType #27:#24 // THU:LEnumTest;
#61 = NameAndType #28:#24 // FRI:LEnumTest;
#62 = NameAndType #29:#24 // SAT:LEnumTest;
#63 = NameAndType #30:#24 // SUN:LEnumTest;
#64 = Utf8 java/lang/Enum
#65 = Utf8 clone
#66 = Utf8 ()Ljava/lang/Object;
#67 = Utf8 (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
{
public static final EnumTest MON;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest TUE;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest WED;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest THU;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest FRI;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest SAT;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final EnumTest SUN;
descriptor: LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static EnumTest[] values();
descriptor: ()[LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #1 // Field $VALUES:[LEnumTest;
3: invokevirtual #2 // Method "[LEnumTest;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LEnumTest;"
9: areturn
LineNumberTable:
line 1: 0
public static EnumTest valueOf(java.lang.String);
descriptor: (Ljava/lang/String;)LEnumTest;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #4 // class EnumTest
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class EnumTest
9: areturn
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: new #4 // class EnumTest
3: dup
4: ldc #7 // String MON
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field MON:LEnumTest;
13: new #4 // class EnumTest
16: dup
17: ldc #10 // String TUE
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field TUE:LEnumTest;
26: new #4 // class EnumTest
29: dup
30: ldc #12 // String WED
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field WED:LEnumTest;
39: new #4 // class EnumTest
42: dup
43: ldc #14 // String THU
45: iconst_3
46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
49: putstatic #15 // Field THU:LEnumTest;
52: new #4 // class EnumTest
55: dup
56: ldc #16 // String FRI
58: iconst_4
59: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
62: putstatic #17 // Field FRI:LEnumTest;
65: new #4 // class EnumTest
68: dup
69: ldc #18 // String SAT
71: iconst_5
72: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
75: putstatic #19 // Field SAT:LEnumTest;
78: new #4 // class EnumTest
81: dup
82: ldc #20 // String SUN
84: bipush 6
86: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
89: putstatic #21 // Field SUN:LEnumTest;
92: bipush 7
94: anewarray #4 // class EnumTest
97: dup
98: iconst_0
99: getstatic #9 // Field MON:LEnumTest;
102: aastore
103: dup
104: iconst_1
105: getstatic #11 // Field TUE:LEnumTest;
108: aastore
109: dup
110: iconst_2
111: getstatic #13 // Field WED:LEnumTest;
114: aastore
115: dup
116: iconst_3
117: getstatic #15 // Field THU:LEnumTest;
120: aastore
121: dup
122: iconst_4
123: getstatic #17 // Field FRI:LEnumTest;
126: aastore
127: dup
128: iconst_5
129: getstatic #19 // Field SAT:LEnumTest;
132: aastore
133: dup
134: bipush 6
136: getstatic #21 // Field SUN:LEnumTest;
139: aastore
140: putstatic #1 // Field $VALUES:[LEnumTest;
143: return
LineNumberTable:
line 2: 0
line 1: 92
}
Signature: #48 // Ljava/lang/Enum<LEnumTest;>;
SourceFile: "EnumTest.java"
反编译查看源码:
public final class EnumTest extends Enum
{
public static EnumTest[] values()
{
return (EnumTest[])$VALUES.clone();
}
public static EnumTest valueOf(String name)//根据名字返回枚举常量
{
return (EnumTest)Enum.valueOf(EnumTest, name);
}
private EnumTest(String s, int i) //构造方法私有化
{
super(s, i);
}
public static final EnumTest MON;//静态常量
public static final EnumTest TUE;
public static final EnumTest WED;
public static final EnumTest THU;
public static final EnumTest FRI;
public static final EnumTest SAT;
public static final EnumTest SUN;
private static final EnumTest $VALUES[];
static
{
MON = new EnumTest("MON", 0);
TUE = new EnumTest("TUE", 1);
WED = new EnumTest("WED", 2);
THU = new EnumTest("THU", 3);
FRI = new EnumTest("FRI", 4);
SAT = new EnumTest("SAT", 5);
SUN = new EnumTest("SUN", 6);
$VALUES = (new EnumTest[] {
MON, TUE, WED, THU, FRI, SAT, SUN
});
}
}
1. 枚举类其实就是一个普通的java类,默认继承了Enum。
2. 枚举类MON就相当于创建了一个类的实例,静态的
枚举实现switch-case:
public static void main(String[] args) {
WeekEnum test = WeekEnum.FRI;
switch (test) {
case MON:
System.out.println("星期一");
break;
case TUE:
System.out.println("星期二");
break;
case WED:
System.out.println("星期三");
break;
case THU:
System.out.println("星期四");
break;
case SAT:
System.out.println("星期五");
break;
case FRI:
System.out.println("星期六");
break;
default:
System.out.println("星期日");
break;
}
}
汇编指令
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field WeekEnum.FRI:LWeekEnum;
3: astore_1
4: getstatic #3 // Field Test$1.$SwitchMap$WeekEnum:[I
7: aload_1
8: invokevirtual #4 // Method WeekEnum.ordinal:()I
11: iaload
12: lookupswitch { // 2
1: 40
2: 51
default: 62
}
40: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
43: ldc #6 // String 1
45: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: goto 70
51: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
54: ldc #8 // String 2
56: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
59: goto 70
62: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
65: ldc #9 // String sleep
67: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
70: return
}
网友评论