1.javap命令是什么?
可以通过javap命令看到java程序在执行过程中,每一句代码真正地做了什么,包括cpu的指令和jvm具体做了什么,可以在发生一些错误或者奇怪的事情的时候,知道为什么会这样。
javap是jdk自带的反解析工具。作用是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。
这些信息当中,有些信息,比如本地变量表、指令和代码偏移映射表,常量池中的方法的参数名称等,需要在使用javac编译成class文件时,指定参数才能输出。使用javac -g xx.java就可以生成所有相关的信息了。
通过局部变量表,我们可以查看局部变量的作用域范围,所在槽位等信息,甚至可以看到槽位复用等信息。
javap的用法格式
javap
其中classes就是你要反编译的class文件。不需要带后缀.class。
命令行中直接输入javap或者javap -help可以看到javap的options:
用法: javap <options> <classes>
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
--module <模块>, -m <模块> 指定包含要反汇编的类的模块
--module-path <路径> 指定查找应用程序模块的位置
--system <jdk> 指定查找系统模块的位置
--class-path <路径> 指定查找用户类文件的位置
-classpath <路径> 指定查找用户类文件的位置
-cp <路径> 指定查找用户类文件的位置
-bootclasspath <路径> 覆盖引导类文件的位置
一般常用的是-v -l -c三个选项
javap -v classxx,不仅会输出行号、本地变量表信息、反编译汇编代码,还会输出当前类用到的常量池等信息。
javap -l 会输出行号和本地变量表信息
javap -c 会对当前class字节码进行反编译生成汇编代码。
也可以通过jclasslib工具来看到上面的信息
2.一些测试
主要介绍code区(汇编指令)、局部变量表和代码偏移映射三个部分
创建一个TestDate.java文件
import java.util.Date;
public class TestDate {
private int count = 0;
public static void main(String[] args) {
TestDate testDate = new TestDate();
testDate.test1();
}
public void test1(){
Date date = new Date();
String name1 = "wangerbei";
test2(date,name1);
System.out.println(date+name1);
}
public void test2(Date dateP,String name2){
dateP = null;
name2 = "zhangsan";
}
public void test3(){
count++;
}
public void test4(){
int a = 0;
{
int b = 0;
b = a+1;
}
int c = a+1;
}
}
使用命令:javac – g TestDate.java,生成一个TestDate.class文件
再使用javap命令对字节码文件进行反汇编,使用命令javap -c -l TestDate
此时不需要加后缀.class
Compiled from "TestDate.java"
public class TestDate {
//默认的构造方法,在构造方法执行时完成一些初始化操作,包括一些成员变量的初始化赋值等
public TestDate();
Code:
0: aload_0 //从本地变量表中加载索引为0的变量的值,也就是this的引用,压入栈
1: invokespecial #1 // 调用方法 java/lang/Object."<init>":()V 完成this对象的初始化
4: aload_0 //
5: iconst_0
6: putfield #2 // Field count:I
9: return
LineNumberTable:
line 2: 0
line 4: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this LTestDate;
public static void main(java.lang.String[]);
Code:
0: new #3 // class TestDate
3: dup
4: invokespecial #4 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #5 // Method test1:()V
12: return
LineNumberTable:
line 7: 0
line 8: 8
line 9: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 args [Ljava/lang/String;
8 5 1 testDate LTestDate;
public void test1();
Code:
0: new #6 // class java/util/Date
3: dup
4: invokespecial #7 // Method java/util/Date."<init>":()V
7: astore_1
8: ldc #8 // String wangerbei
10: astore_2
11: aload_0
12: aload_1
13: aload_2
14: invokevirtual #9 // Method test2:(Ljava/util/Date;Ljava/lang/String;)V
17: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
20: aload_1
21: aload_2
22: invokedynamic #11, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/util/Date;Ljava/lang/String;)Ljava/lang/String;
27: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: return
LineNumberTable:
line 12: 0
line 13: 8
line 14: 11
line 15: 17
line 16: 30
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 this LTestDate;
8 23 1 date Ljava/util/Date;
11 20 2 name1 Ljava/lang/String;
public void test2(java.util.Date, java.lang.String);
Code:
0: aconst_null
1: astore_1
2: ldc #13 // String zhangsan
4: astore_2
5: return
LineNumberTable:
line 19: 0
line 20: 2
line 21: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this LTestDate;
0 6 1 dateP Ljava/util/Date;
0 6 2 name2 Ljava/lang/String;
public void test3();
Code:
0: aload_0
1: dup
2: getfield #2 // Field count:I
5: iconst_1
6: iadd
7: putfield #2 // Field count:I
10: return
LineNumberTable:
line 24: 0
line 25: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this LTestDate;
public void test4();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_1
5: iconst_1
6: iadd
7: istore_2
8: iload_1
9: iconst_1
10: iadd
11: istore_2
12: return
LineNumberTable:
line 28: 0
line 30: 2
line 31: 4
line 33: 8
line 34: 12
LocalVariableTable:
Start Length Slot Name Signature
4 4 2 b I
0 13 0 this LTestDate;
2 11 1 a I
12 1 2 c I
}