javap 命令的常用方式
javap 是 Java 开发工具包(JDK)中的一个命令行工具,用于反编译 Java 类文件并显示其详细信息,包括类的成员(字段、方法)、字节码、常量池以及方法的签名信息。方法的签名(Method Signature)包含了方法的名称、参数类型和返回类型,这在反射编程和理解类的结构时非常有用。
以下是使用 javap 获取 Java 类中方法签名信息的详细指南:
1. 基本用法
编译 Java 文件
首先,确保你已经编译了 Java 文件,生成了对应的 .class 文件。例如,假设有一个 Example.java 文件:
// Example.java
public class Example {
private int number;
public String message;
public Example() {}
public Example(int num, String msg) {
this.number = num;
this.message = msg;
}
public int getNumber() {
return number;
}
public void setNumber(int num) {
this.number = num;
}
public String getMessage() {
return message;
}
public void setMessage(String msg) {
this.message = msg;
}
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
编译该文件:
javac Example.java
这将生成 Example.class 文件。
使用 javap 查看类的基本信息
要查看类的基本信息,包括方法签名,可以使用以下命令:
javap Example
输出示例:
Compiled from "Example.java"
public class Example {
private int number;
public java.lang.String message;
public Example();
public Example(int, java.lang.String);
public int getNumber();
public void setNumber(int);
public java.lang.String getMessage();
public void setMessage(java.lang.String);
public static void main(java.lang.String[]);
}
在这个输出中,每个方法后面的括号内列出了参数类型,返回类型则在方法名之前。例如:
public int getNumber()的签名是(I)I(在字节码中表示),但在javap的默认输出中以更易读的形式展示。public void setNumber(int)的签名是(I)V。
不过,默认的 javap 输出并不直接显示方法的完整签名(包括参数类型和返回类型的内部表示)。要获取更详细的签名信息,需要使用额外的选项。
2. 使用 -s 选项显示方法签名
javap 的 -s 选项可以显示方法的签名,包括参数类型和返回类型的内部名称(使用 JVM 内部类型表示法)。
命令
javap -s Example
输出示例
Compiled from "Example.java"
public class Example {
private int number;
descriptor: I
public java.lang.String message;
descriptor: Ljava/lang/String;
public Example();
descriptor: ()V
public Example(int, java.lang.String);
descriptor: (ILjava/lang/String;)V
public int getNumber();
descriptor: ()I
public void setNumber(int);
descriptor: (I)V
public java.lang.String getMessage();
descriptor: ()Ljava/lang/String;
public void setMessage(java.lang.String);
descriptor: (Ljava/lang/String;)V
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
}
解释
descriptor字段展示了方法的签名,使用 JVM 的内部类型表示法:I表示intLjava/lang/String;表示java.lang.StringV表示void[Ljava/lang/String;表示String[]- 参数类型按顺序排列在括号内,返回类型在括号后。
例如:
public int getNumber();的描述符是()I,表示无参数,返回int。public void setNumber(int);的描述符是(I)V,表示接受一个int参数,返回void。public Example(int, java.lang.String);的描述符是(ILjava/lang/String;)V,表示接受一个int和一个String参数,返回void。
3. 使用 -p 选项显示所有类和成员(包括私有)
默认情况下,javap 不会显示类的私有成员。如果你想查看所有成员(包括私有的),可以使用 -p 选项。
命令
javap -p Example
输出示例
Compiled from "Example.java"
public class Example {
private int number;
public java.lang.String message;
public Example();
public Example(int, java.lang.String);
public int getNumber();
public void setNumber(int);
public java.lang.String getMessage();
public void setMessage(java.lang.String);
public static void main(java.lang.String[]);
}
这与不加 -p 的输出类似,但如果类中有私有成员且未使用 -p,则不会显示这些私有成员。
4. 使用 -v 选项显示详细信息(包括字节码)
-v 选项会显示更详细的信息,包括常量池、方法字节码等。这对于深入理解类的内部结构非常有用。
命令
javap -v Example
输出示例
输出内容较多,这里仅展示部分相关部分:
Classfile /path/to/Example.class
Last modified ...; size 500 bytes
MD5 checksum ...
Compiled from "Example.java"
public class Example
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#17 // java/lang/Object."<init>":()V
#2 = Fieldref #5.#18 // Example.number:I
#3 = Fieldref #5.#19 // Example.message:Ljava/lang/String;
#4 = String #20 // Hello, World!
#5 = Class #21 // Example
#6 = Class #22 // java/lang/Object
#7 = Utf8 number
#8 = Utf8 I
#9 = Utf8 message
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 LocalVariableTable
#16 = Utf8 this
#17 = NameAndType #11:#12 // "<init>":()V
#18 = NameAndType #7:#8 // number:I
#19 = NameAndType #9:#10 // message:Ljava/lang/String;
#20 = Utf8 Hello, World!
#21 = Utf8 Example
#22 = Utf8 java/lang/Object
{
private int number;
descriptor: I
flags: ACC_PRIVATE
public java.lang.String message;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC
public Example();
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 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LExample;
public Example(int, java.lang.String);
descriptor: (ILjava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #2 // Field number:I
9: aload_0
10: aload_2
11: putfield #3 // Field message:Ljava/lang/String;
14: return
LineNumberTable:
line 7: 0
line 8: 4
line 9: 14
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this LExample;
0 15 1 num I
0 15 2 msg Ljava/lang/String;
... (其他方法类似)
}
解释
descriptor字段在常量池和方法定义中展示了方法的签名。- 在
Code部分,可以看到字节码指令,这对于理解方法的具体实现非常有用。
5. 使用 -s 和 -p 结合查看所有方法的签名
如果你想查看类中所有方法的签名,包括私有方法,可以结合使用 -s 和 -p 选项:
命令
javap -sp Example
注意:javap 不支持直接组合 -s 和 -p 选项。要同时显示签名和所有成员,可以分两步进行,或者使用其他工具(如反射 API)。
不过,你可以分别使用 -s 和 -p 来获取所需信息:
-
查看签名:
javap -s Example -
查看所有成员(包括私有):
javap -p Example
如果你确实需要在一个命令中同时获取签名和所有成员的信息,可以考虑编写一个脚本或使用其他工具来解析 javap 的输出。
6. 示例总结
假设你有以下类 Calculator.java:
// Calculator.java
public class Calculator {
private int value;
public Calculator(int initialValue) {
this.value = initialValue;
}
public int getValue() {
return value;
}
public void setValue(int newValue) {
this.value = newValue;
}
public int add(int a, int b) {
return a + b;
}
public static double multiply(double x, double y) {
return x * y;
}
}
编译
javac Calculator.java
查看方法签名
javap -s Calculator
输出示例
Compiled from "Calculator.java"
public class Calculator {
private int value;
descriptor: I
public Calculator(int);
descriptor: (I)V
public int getValue();
descriptor: ()I
public void setValue(int);
descriptor: (I)V
public int add(int, int);
descriptor: (II)I
public static double multiply(double, double);
descriptor: (DD)D
}
解释各方法签名:
-
public Calculator(int);- 描述符:
(I)V - 表示接受一个
int参数,返回void。
- 描述符:
-
public int getValue();- 描述符:
()I - 表示无参数,返回
int。
- 描述符:
-
public void setValue(int);- 描述符:
(I)V - 表示接受一个
int参数,返回void。
- 描述符:
-
public int add(int, int);- 描述符:
(II)I - 表示接受两个
int参数,返回int。
- 描述符:
-
public static double multiply(double, double);- 描述符:
(DD)D - 表示接受两个
double参数,返回double。
- 描述符:
7. 进一步了解 JVM 类型描述符
JVM 使用特定的符号来表示类型,这在方法签名中非常常见。以下是一些常见的类型描述符:
| Java 类型 | JVM 描述符 |
|---|---|
byte |
B |
char |
C |
double |
D |
float |
F |
int |
I |
long |
J |
short |
S |
boolean |
Z |
void |
V |
类类型(如 String) |
L + 完全限定名 + ; |
| 数组类型 | [ + 基本类型或类类型 |
示例:
String的描述符:Ljava/lang/String;int[]的描述符:[IString[][]的描述符:[[Ljava/lang/String;
8. 使用 javap 查看其他信息
除了方法签名,javap 还可以显示类的其他详细信息,例如:
查看常量池
javap -v Example | grep -A 1 "Constant pool"
查看字段和方法的访问标志
javap -v Example | grep -E "flags|Field|Method"
查看字节码
javap -c Example
这将显示每个方法的字节码指令。
9. 总结
javap 是一个强大的工具,可以帮助开发者深入了解 Java 类的内部结构,包括方法签名。通过结合不同的选项(如 -s、-p、-v 等),你可以获取所需的详细信息。以下是常用的命令总结:
-
查看方法签名:
javap -s 类名 -
查看所有成员(包括私有):
javap -p 类名 -
查看详细信息(包括常量池和字节码):
javap -v 类名 -
查看反编译的代码(部分版本支持):
javap -c 类名
通过熟练使用 javap,你可以更好地理解 Java 类的结构,进行调试、学习和开发工作。
如果你有更多关于 javap 或 Java 开发的问题,欢迎继续提问! 😊

浙公网安备 33010602011771号