入门代码很简单:
public class Test {
public static void main(String[] args) {
System.out.println("a");
}
}
Classfile /D:/work/IDEAWorkSpace/my-study/io/target/classes/com/jathonkatu/io/bio/Test.class
Last modified 2021-12-27; size 579 bytes
MD5 checksum 3bae36d299be64b900ed5c05b586bf20
Compiled from "Test.java"
public class com.jathonkatu.io.bio.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#21 // java/lang/Object."<init>":()V
#2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #24 // a
#4 = Methodref #25.#26 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #27 // com/jathonkatu/io/bio/Test
#6 = Class #28 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/jathonkatu/io/bio/Test;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 MethodParameters
#19 = Utf8 SourceFile
#20 = Utf8 Test.java
#21 = NameAndType #7:#8 // "<init>":()V
#22 = Class #29 // java/lang/System
#23 = NameAndType #30:#31 // out:Ljava/io/PrintStream;
#24 = Utf8 a
#25 = Class #32 // java/io/PrintStream
#26 = NameAndType #33:#34 // println:(Ljava/lang/String;)V
#27 = Utf8 com/jathonkatu/io/bio/Test
#28 = Utf8 java/lang/Object
#29 = Utf8 java/lang/System
#30 = Utf8 out
#31 = Utf8 Ljava/io/PrintStream;
#32 = Utf8 java/io/PrintStream
#33 = Utf8 println
#34 = Utf8 (Ljava/lang/String;)V
{
public com.jathonkatu.io.bio.Test();
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 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jathonkatu/io/bio/Test;
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: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String a
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 10: 0
line 11: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
MethodParameters:
Name Flags
args
}
SourceFile: "Test.java"
具体细节我们看进阶代码
进阶代码很简单:
public class Test {
public static void main(String[] args) {
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("arthas");
}
}
我们来看看javap -c -p -v Test.class之后的结果
以下所有// Jathonkatu则是我自己写的注释
javac的时候可以用-g:none或-g:vars选项来取消或要求生成LocalVariableTable的参数(也就是字段名)取消了会用var0,arg0之类的代替
可以用-g:none或-g:lines取消或者生成LineNumberTable
Classfile /D:/work/IDEAWorkSpace/my-study/io/target/classes/com/jathonkatu/io/bio/Test.class // Jathonkatu 这里是说明class路径
Last modified 2021-12-27; size 1429 bytes // Jathonkatu 最后修改日期,文件大小
MD5 checksum 954dbfeb9e7546cc4db907ed0b60a2bc // Jathonkatu 用以校验的MD5的码
Compiled from "Test.java" // Jathonkatu 编译类名
public class com.jathonkatu.io.bio.Test // Jathonkatu 类地址
minor version: 0 // Jathonkatu .0
major version: 52 // Jathonkatu 52 52.0-> jdk8
flags: ACC_PUBLIC, ACC_SUPER // Jathonkatu public类型,使用invokespecial字节码指令. 识别一些类或 者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract 类型;如果是类的话,是否被声明为final;等等
Constant pool: // Jathonkatu 常量池
#1 = Methodref #8.#31 // java/lang/Object."<init>":()V // Jathonkatu 方法符号
#2 = InvokeDynamic #0:#37 // #0:accept:()Ljava/util/function/Consumer; // Jathonkatu 动态调用点 consumer的accept方法
#3 = String #38 // arthas // Jathonkatu 字符串arthas 我们自己定义的
#4 = InterfaceMethodref #39.#40 // java/util/function/Consumer.accept:(Ljava/lang/Object;)V // Jathonkatu 接口中方法的符号引用
#5 = Fieldref #41.#42 // java/lang/System.out:Ljava/io/PrintStream; // Jathonkatu 字段的符号引用 System类中的字段out 是一个PrintStream的类型
#6 = Methodref #43.#44 // java/io/PrintStream.println:(Ljava/lang/String;)V // Jathonkatu 方法符号引用 调用printStream的prinln方法(参数是String)
#7 = Class #45 // com/jathonkatu/io/bio/Test // Jathonkatu 类或接口的符号引用 类全名
#8 = Class #46 // java/lang/Object // Jathonkatu 类或接口的符号引用
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable // Jathonkatu 行号与字节码指令的对应关系
#13 = Utf8 LocalVariableTable // Jathonkatu 方法的局部变量描述
#14 = Utf8 this
#15 = Utf8 Lcom/jathonkatu/io/bio/Test; // Jathonkatu 类名
#16 = Utf8 main // Jathonkatu 方法名
#17 = Utf8 ([Ljava/lang/String;)V // Jathonkatu String数组值
#18 = Utf8 args // Jathonkatu 变量名 args
#19 = Utf8 [Ljava/lang/String; // Jathonkatu String数组值
#20 = Utf8 consumer // Jathonkatu 变量名 consumer
#21 = Utf8 Ljava/util/function/Consumer; // 对象Consumer
#22 = Utf8 LocalVariableTypeTable // 方法的局部变量描述 只是一个标识符
#23 = Utf8 Ljava/util/function/Consumer<Ljava/lang/String;>; // 对象Consumer<String>
#24 = Utf8 MethodParameters // Jathonkatu 方法入参
#25 = Utf8 lambda$main$0 // Jathonkatu 方法名
#26 = Utf8 (Ljava/lang/String;)V // Jathonkatu String变量值
#27 = Utf8 s // Jathonkatu 变量名
#28 = Utf8 Ljava/lang/String; // Jathonkatu String类型
#29 = Utf8 SourceFile // Jathonkatu 来源文件
#30 = Utf8 Test.java // Jathonkatu java文件名
#31 = NameAndType #9:#10 // "<init>":()V // Jathonkatu 实例构造器(无参数)部分符号引用
#32 = Utf8 BootstrapMethods // Jathonkatu 用于保存invokedynamic指令引用的引导方法限定符
#33 = MethodHandle #6:#47 // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/
invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; // Jathonkatu 方法句柄
#34 = MethodType #48 // (Ljava/lang/Object;)V // 方法类型
#35 = MethodHandle #6:#49 // invokestatic com/jathonkatu/io/bio/Test.lambda$main$0:(Ljava/lang/String;)V
#36 = MethodType #26 // (Ljava/lang/String;)V // Jathonkatu 方法类型
#37 = NameAndType #50:#51 // accept:()Ljava/util/function/Consumer;// Jathonkatu 方法引用 accept
#38 = Utf8 arthas // Jathonkatu 字符串arthas
#39 = Class #52 // java/util/function/Consumer // Jathonkatu 类类型Consumer
#40 = NameAndType #50:#48 // accept:(Ljava/lang/Object;)V // Jathonkatu 调用方法accept(object)
#41 = Class #53 // java/lang/System // Jathonkatu System类
#42 = NameAndType #54:#55 // out:Ljava/io/PrintStream; // Jathonkatu 字段类型out字段的类为PrintStream
#43 = Class #56 // java/io/PrintStream // Jathonkatu 类型
#44 = NameAndType #57:#26 // println:(Ljava/lang/String;)V // Jathonkatu 引用方法println
#45 = Utf8 com/jathonkatu/io/bio/Test // Jathonkatu 字符串(用来表述类的包路径)
#46 = Utf8 java/lang/Object // Jathonkatu 父类
#47 = Methodref #58.#59 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/Method
Handle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#48 = Utf8 (Ljava/lang/Object;)V
#49 = Methodref #7.#60 // com/jathonkatu/io/bio/Test.lambda$main$0:(Ljava/lang/String;)V
#50 = Utf8 accept
#51 = Utf8 ()Ljava/util/function/Consumer;
#52 = Utf8 java/util/function/Consumer
#53 = Utf8 java/lang/System
#54 = Utf8 out
#55 = Utf8 Ljava/io/PrintStream;
#56 = Utf8 java/io/PrintStream
#57 = Utf8 println
#58 = Class #61 // java/lang/invoke/LambdaMetafactory
#59 = NameAndType #62:#66 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType
;)Ljava/lang/invoke/CallSite;
#60 = NameAndType #25:#26 // lambda$main$0:(Ljava/lang/String;)V
#61 = Utf8 java/lang/invoke/LambdaMetafactory
#62 = Utf8 metafactory
#63 = Class #68 // java/lang/invoke/MethodHandles$Lookup // Jathonkatu 类型
#64 = Utf8 Lookup // Jathonkatu 跳转
#65 = Utf8 InnerClasses // Jathonkatu 内部类文件
#66 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#67 = Class #69 // java/lang/invoke/MethodHandles
#68 = Utf8 java/lang/invoke/MethodHandles$Lookup
#69 = Utf8 java/lang/invoke/MethodHandles
{
public com.jathonkatu.io.bio.Test(); // Jathonkatu 类构造方法
descriptor: ()V // Jathonkatu 返回一个v的类型(就是占位符)
flags: ACC_PUBLIC // Jathonkatu public关键字
Code:
stack=1, locals=1, args_size=1 // Jathonkatu 栈深度,本地方法,参数个数
0: aload_0 // Jathonkatu 应该将“this”推送到堆栈上
1: invokespecial #1 // Method java/lang/Object."<init>":()V // Jathonkatu 调用初始化方法
4: return // Jathonkatu 返回
LineNumberTable: // Jathonkatu 行号与字节码指令对应关系 前者是字节码行号,后者是源码行号
line 9: 0
LocalVariableTable: // Jathonkatu 方法的局部变量描述
Start Length Slot Name Signature // Jathonkatu 局部变量的生命周期的字节码偏移量开始,覆盖长度(前两个结合就是局部变量在字节码中的作用域),局部变量在栈帧局部变量表中solt的位置,如果是64位的就是solt和solt+1(double,long),局部变量的名称,局部变量的描述符(用于支持泛型)
0 5 0 this Lcom/jathonkatu/io/bio/Test;
public static void main(java.lang.String[]); //Jathonkatu main方法
descriptor: ([Ljava/lang/String;)V // Jathonkatu 描述符
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer; // Jathonkatu 动态调用
5: astore_1 // Jathonkatu JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1
6: aload_1 // Jathonkatu 获取第一个参数(args)
7: ldc #3 // String arthas // Jathonkatu 该系列命令负责把数值常量或String常量值从常量池中推送至栈顶。该命令后面需要给一个表示常量在常量池中位置(编号)的参数 也就是把字节码第三行的arthas推送到栈顶
9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V // Jathonkatu 索引,将字节码第四行和只想第二行
14: return // 返回
LineNumberTable:
line 11: 0
line 12: 6
line 13: 14
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 args [Ljava/lang/String;
6 9 1 consumer Ljava/util/function/Consumer;
LocalVariableTypeTable:
Start Length Slot Name Signature
6 9 1 consumer Ljava/util/function/Consumer<Ljava/lang/String;>;
MethodParameters: // Jathonkatu 记录形参个数,参数名
Name Flags
args
private static void lambda$main$0(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; // Jathonkatu 获取静态变量
3: aload_0 // Jathonkatu 应该将“this”推送到堆栈上
4: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V // 调用虚方法,运行期动态查找的过程
7: return
LineNumberTable:
line 11: 0
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 s Ljava/lang/String;
MethodParameters:
Name Flags
s synthetic
}
SourceFile: "Test.java" // Jathonkatu 源文件的文件名
InnerClasses: // Jathonkatu 内部类列表
public static final #64= #63 of #67; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles // lookup类是MethodHandles的内部类
BootstrapMethods: // Jathonkatu 用于保存invokedynamic指令引用的引导方法限定符
0: #33 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invok
e/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#34 (Ljava/lang/Object;)V
#35 invokestatic com/jathonkatu/io/bio/Test.lambda$main$0:(Ljava/lang/String;)V
#36 (Ljava/lang/String;)V