JVM-01
2019-06-19 本文已影响0人
平头哥2
编写HelloWorld.java
public class HelloWorld{
public static void main(String[] args){
System.out.println("HelloWorld");
}
}
编译:
javac HelloWorld.java
javap的使用:
D:\>javap
用法: javap <options> <classes>
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
-classpath <path> 指定查找用户类文件的位置
-cp <path> 指定查找用户类文件的位置
-bootclasspath <path> 覆盖引导类文件的位置
其中-c -v -l -p -s
是最常用的
-c 选项
:
$ javap -c HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld(); // ##这里默认会添加一个构造方法
Code:
0: aload_0 //
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);//## main函数
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String HelloWorld
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
解释:
aload_0 这个操作码是 aload_x 格式操作码中的一个。它们用来把**对象引用**加载到操作数栈。 x 表示正在被访问的局部变量数组的位置。在这里的 0 代表什么呢?我们知道非静态的函数都有第一个默认参数,那就是 this,这里的 aload_0 就是把 this 入栈
-
invokespecial #1,invokespecial 指令调用实例初始化方法、私有方法、父类方法,#1 指的是常量池中的第一个,这里是方法引用
java/lang/Object."<init>":()V,也即构造器函数
return,这个操作码属于 ireturn、lreturn、freturn、dreturn、areturn 和 return 操作码组中的一员,其中 i 表示 int,返回整数,同类的还有 l 表示 long,f 表示 float,d 表示 double,a 表示 对象引用。没有前缀类型字母的 return 表示返回 void
-
getstatic #2,getstatic 获取指定类的静态域,并将其值压入栈顶,#2 代表常量池中的第 2 个,这里表示的是
java/lang/System.out:Ljava/io/PrintStream;,其实就是java.lang.System 类的静态变量 out(类型是 PrintStream)
ldc #3、,ldc 用来将常量从运行时常量池压栈到操作数栈,#3 代表常量池的第三个(字符串 Hello, World)
invokevirtual #4,invokevirutal 指令调用一个对象的实例方法,#4 表示 PrintStream.println(String) 函数引用,并把栈顶两个元素出栈
-v选项
$ javap -v HelloWorld.class
Classfile /D:/ideaproject/jvm/HelloWorld.class
Last modified 2019-6-19; size 411 bytes
MD5 checksum 30c120f376b16361b854fd5c0d695ea6
Compiled from "HelloWorld.java"
public class HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."<init>":()V
#2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #18 // HelloWorld
#4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #18 // HelloWorld
#6 = Class #21 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 SourceFile
#14 = Utf8 HelloWorld.java
#15 = NameAndType #7:#8 // "<init>":()V
#16 = Class #22 // java/lang/System
#17 = NameAndType #23:#24 // out:Ljava/io/PrintStream;
#18 = Utf8 HelloWorld
#19 = Class #25 // java/io/PrintStream
#20 = NameAndType #26:#27 // println:(Ljava/lang/String;)V
#21 = Utf8 java/lang/Object
#22 = Utf8 java/lang/System
#23 = Utf8 out
#24 = Utf8 Ljava/io/PrintStream;
#25 = Utf8 java/io/PrintStream
#26 = Utf8 println
#27 = 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
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 HelloWorld
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
}
SourceFile: "HelloWorld.java"
-l选项
$ javap -l HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
LineNumberTable:
line 3: 0
line 4: 8
}
-s选项:
输出签名的类型描述符
$ javap -s HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();//构造方法
descriptor: ()V //描述: ()表示没有参数,V表示返回值为void
public static void main(java.lang.String[]); //main方法
descriptor: ([Ljava/lang/String;)V // ([Ljava/lang/String;)表示参数为数组
}
修改java代码如下:
public class HelloWorld{
public int test01(byte b1, short s, int a, long l2, float f1, double d, char c, boolean bool,Integer it,String str){
return 0;
}
}
重新编译,查看方法签名
$ javap -s HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
descriptor: ()V
public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
descriptor: (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
}
查看调试信息:
编译阶段加上-g参数:
$ javac -g HelloWorld.java
-l 选项
$ javap -l HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LHelloWorld;
//this表明构造方法默认第一个参数是this,LHelloWorld,表示构造方法名字和类名一样
public static void main(java.lang.String[]);
LineNumberTable:
line 4: 0
line 5: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
//args:参数名字,[Ljava/lang/String:表示参数为String数组,数组以 '[L' 开头
public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LHelloWorld;//this表明成员方法默认第一个参数是this
0 2 1 b1 B //第二个参数名字是b1, 类型为byte,B代表byte
0 2 2 s S //第三个参数名字是s, 类型为short,S代表short
0 2 3 a I //第四个参数名字是a, 类型为int,I代表int
0 2 4 l2 J //第五个参数名字是l2, 类型为long,J代表long
0 2 6 f1 F //第六个参数名字是f1, 类型为float,F代表float
0 2 7 d D //第七个参数名字是d, 类型为short,D代表double
0 2 9 c C //第八个参数名字是c, 类型为char,C代表char
0 2 10 bool Z //第九个参数名字是bool, 类型为boolean,Z代表boolean
0 2 11 it Ljava/lang/Integer; //第十个参数名字是it, 类型为Integer
//引用类型以L开头
0 2 12 str Ljava/lang/String; //第十一个参数名字是str, 类型为String
}
-v 选项
$ javap -v HelloWorld.class
Classfile /D:/ideaproject/jvm/HelloWorld.class
Last modified 2019-6-19; size 874 bytes
MD5 checksum ee15f31a14c1582634907a7504bf4cf7
Compiled from "HelloWorld.java"
public class HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#42 // java/lang/Object."<init>":()V
#2 = Fieldref #43.#44 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #45 // helloworld
#4 = Methodref #46.#47 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #48 // HelloWorld
#6 = Class #49 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 LHelloWorld;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 test01
#19 = Utf8 (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
#20 = Utf8 b1
#21 = Utf8 B
#22 = Utf8 s
#23 = Utf8 S
#24 = Utf8 a
#25 = Utf8 I
#26 = Utf8 l2
#27 = Utf8 J
#28 = Utf8 f1
#29 = Utf8 F
#30 = Utf8 d
#31 = Utf8 D
#32 = Utf8 c
#33 = Utf8 C
#34 = Utf8 bool
#35 = Utf8 Z
#36 = Utf8 it
#37 = Utf8 Ljava/lang/Integer;
#38 = Utf8 str
#39 = Utf8 Ljava/lang/String;
#40 = Utf8 SourceFile
#41 = Utf8 HelloWorld.java
#42 = NameAndType #7:#8 // "<init>":()V
#43 = Class #50 // java/lang/System
#44 = NameAndType #51:#52 // out:Ljava/io/PrintStream;
#45 = Utf8 helloworld
#46 = Class #53 // java/io/PrintStream
#47 = NameAndType #54:#55 // println:(Ljava/lang/String;)V
#48 = Utf8 HelloWorld
#49 = Utf8 java/lang/Object
#50 = Utf8 java/lang/System
#51 = Utf8 out
#52 = Utf8 Ljava/io/PrintStream;
#53 = Utf8 java/io/PrintStream
#54 = Utf8 println
#55 = 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 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 helloworld
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 4: 0
line 5: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
descriptor: (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=13, args_size=11 //参数个数为11
0: iconst_0
1: ireturn
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LHelloWorld;
0 2 1 b1 B
0 2 2 s S
0 2 3 a I
0 2 4 l2 J
0 2 6 f1 F
0 2 7 d D
0 2 9 c C
0 2 10 bool Z
0 2 11 it Ljava/lang/Integer;
0 2 12 str Ljava/lang/String;
}
SourceFile: "HelloWorld.java"
以16进制查看HelloWorld.class文件:
# 将class文件转换成16进制
$ xxd HelloWorld.class HelloWorld.txt
$ ls
HelloWorld.class HelloWorld.java HelloWorld.txt
$ cat HelloWorld.txt
00000000: cafe babe 0000 0034 001c 0a00 0600 0f09 .......4........
00000010: 0010 0011 0800 120a 0013 0014 0700 1207 ................
00000020: 0015 0100 063c 696e 6974 3e01 0003 2829 .....<init>...()
00000030: 5601 0004 436f 6465 0100 0f4c 696e 654e V...Code...LineN
00000040: 756d 6265 7254 6162 6c65 0100 046d 6169 umberTable...mai
00000050: 6e01 0016 285b 4c6a 6176 612f 6c61 6e67 n...([Ljava/lang
00000060: 2f53 7472 696e 673b 2956 0100 0a53 6f75 /String;)V...Sou
00000070: 7263 6546 696c 6501 000f 4865 6c6c 6f57 rceFile...HelloW
00000080: 6f72 6c64 2e6a 6176 610c 0007 0008 0700 orld.java.......
00000090: 160c 0017 0018 0100 0a48 656c 6c6f 576f .........HelloWo
000000a0: 726c 6407 0019 0c00 1a00 1b01 0010 6a61 rld...........ja
000000b0: 7661 2f6c 616e 672f 4f62 6a65 6374 0100 va/lang/Object..
000000c0: 106a 6176 612f 6c61 6e67 2f53 7973 7465 .java/lang/Syste
000000d0: 6d01 0003 6f75 7401 0015 4c6a 6176 612f m...out...Ljava/
000000e0: 696f 2f50 7269 6e74 5374 7265 616d 3b01 io/PrintStream;.
000000f0: 0013 6a61 7661 2f69 6f2f 5072 696e 7453 ..java/io/PrintS
00000100: 7472 6561 6d01 0007 7072 696e 746c 6e01 tream...println.
00000110: 0015 284c 6a61 7661 2f6c 616e 672f 5374 ..(Ljava/lang/St
00000120: 7269 6e67 3b29 5600 2100 0500 0600 0000 ring;)V.!.......
00000130: 0000 0200 0100 0700 0800 0100 0900 0000 ................
00000140: 1d00 0100 0100 0000 052a b700 01b1 0000 .........*......
00000150: 0001 000a 0000 0006 0001 0000 0001 0009 ................
00000160: 000b 000c 0001 0009 0000 0025 0002 0001 ...........%....
00000170: 0000 0009 b200 0212 03b6 0004 b100 0000 ................
00000180: 0100 0a00 0000 0a00 0200 0000 0300 0800 ................
00000190: 0400 0100 0d00 0000 0200 0e ...........
class文件各个部分的解释
-
魔数
cafe babe
class 的魔数为 0xCAFEBABE, 这个魔数是 JVM 识别 .class 文件的标志,虚拟机在加载类文件之前会先检查这四个字节,如果不是 0xCAFEBABE 则拒绝加载该文件