jvm字节码参考
我们使用javap将如下程序的class文件编译获得字节码。
package net.zhaoyu.javapros.test;
public class Test2 {
public static void main(String[] args) {
String str_a = "a";
String str_b = "b";
String str_ab = "a" + "b";
String str_ab1=str_a+str_b;
String str_ab2 = "ab";
System.out.println(str_ab==str_ab1);
System.out.println(str_ab==str_ab2);
String str_new=new String("ab");
}
}
得到的字节码分为多个部分,我主要关注常量池部分和代码指令部分。
Constant pool
字节码的常量池部分定义了class文件使用到的常量,如上程序的部分常量池定义如下:
#1 = Methodref #14.#27 // java/lang/Object."<init>":()V
#2 = String #28 // a
#3 = String #29 // b
#4 = String #30 // ab
#5 = Class #31 // java/lang/StringBuilder
#6 = Methodref #5.#27 // java/lang/StringBuilder."<init>":()V
#7 = Methodref #5.#32 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#8 = Methodref #5.#33 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Fieldref #34.#35 // java/lang/System.out:Ljava/io/PrintStream;
#10 = Methodref #36.#37 // java/io/PrintStream.println:(Z)V
#11 = Class #38 // java/lang/String
#12 = Methodref #11.#39 // java/lang/String."<init>":(Ljava/lang/String;)V
#13 = Class #40 // net/zhaoyu/javapros/test/Test2
#14 = Class #41 // java/lang/Object
#15 = Utf8 <init>
#16 = Utf8 ()V
#17 = Utf8 Code
#18 = Utf8 LineNumberTable
#19 = Utf8 main
#33 = NameAndType #46:#47 // toString:()Ljava/lang/String;
......
- CONSTANT_Class: 类或接口的符号引用。
- CONSTANT_Fieldref: 字段的符号引用。
- CONSTANT_Methodref: 方法的符号引用。
- CONSTANT_InterfaceMethodref: 接口方法的符号引用。
- CONSTANT_Integer: 整型常量。
- CONSTANT_String: 字符串型常量。
- CONSTANT_String: 字符串型常量。
- CONSTANT_Float: 浮点型常量。
- CONSTANT_Double: 双精度浮点型常量。
- CONSTANT_NameAndType: 字段或方法的符号引用。
- CONSTANT_utf8: utf8编码的字符串。
- CONSTANT_MethodHandle: 表示方法句柄。
- CONSTANT_MethodType: 表示方法类型。
- CONSTANT_InvokeDynamic: 表示一个动态方法调用点。
字段描述符
- B byte类型值。
- C char类型值,使用UTF-16编码。
- D double值
- F float类型值。
- I int类型值。
- J long类型值
- LClassName; 类名为ClassName的一个实例。
- S short类型值。
- Z boolean类型值。
- [ 表示一个数组。
方法描述符
例如:
Object m(int i,double d,Thread t){...}
字节码中描述为:
(IDLjava/lang/Thread;)Ljava.lang.Object;
方法字节码
上述程序的方法字节码描述如下:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=7, args_size=1 //stack表示操作栈的大小为2,locals表示本地变量表中有7个变量。args_size参数大小
0: ldc #2 // String a //-将常量值从常量池中推送到栈顶。
2: astore_1 //-将栈顶的引用类型从栈中移出,存储到本地变量表。
3: ldc #3 // String b
5: astore_2
6: ldc #4 // String ab
8: astore_3
9: new #5 // class java/lang/StringBuilder //-创建一个对象,并将其引用值压入栈顶
12: dup //-复制栈顶元素,new后需要复制供invokesepcial使用。
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V //-构造方法的调用
16: aload_1 //-本地变量表1位置的对象入栈顶。
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2 //-本地变量表2位置的对象入栈顶。
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore 4 //-将栈顶元素的值到变量表位置4.
29: ldc #4 // String ab
31: astore 5
33: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_3
37: aload 4
39: if_acmpne 46
42: iconst_1
43: goto 47
46: iconst_0
47: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
50: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
53: aload_3
54: aload 5
56: if_acmpne 63
59: iconst_1
60: goto 64
63: iconst_0
64: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
67: new #11 // class java/lang/String
70: dup
71: ldc #4 // String ab
73: invokespecial #12 // Method java/lang/String."<init>":(Ljava/lang/String;)V
76: astore 6
78: return
LineNumberTable:
line 5: 0
line 6: 3
line 7: 6
line 8: 9
line 9: 29
line 10: 33
line 11: 50
line 12: 67
line 13: 78
......