输出所有方法的列表,以及 java class 文件中的字节数?
output a list of all the methods, and the number of bytes in a java class file?
我想知道如何在 class 文件中获取所有方法的列表以及每个方法的字节数。
例如:
我想要一个主要的源代码,它可以通过 cmd 行参数解析少数 .class 文件,并获取每个 classes.
的上述详细信息
javac myapp classFile1.class classFile2.class ...
请注意:我知道方法列表可以通过 javap className.class
最简单的解决方案是 运行 javap
javap -c -v -p -cp . classFile1
这将转储出所有方法和带有方法长度的字节码。
例如
$ javap -c -v -p -cp . java.lang.Void
Classfile jar:file:/opt/jdk1.8.0_51/jre/lib/rt.jar!/java/lang/Void.class
Last modified 08-Jun-2015; size 454 bytes
MD5 checksum 8a3bdf282569bff4cd7c5fc24cbaee83
Compiled from "Void.java"
public final class java.lang.Void
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
#1 = Methodref #6.#18 // java/lang/Object."<init>":()V
#2 = String #19 // void
#3 = Methodref #20.#21 // java/lang/Class.getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
#4 = Fieldref #5.#22 // java/lang/Void.TYPE:Ljava/lang/Class;
#5 = Class #23 // java/lang/Void
#6 = Class #24 // java/lang/Object
#7 = Utf8 TYPE
#8 = Utf8 Ljava/lang/Class;
#9 = Utf8 Signature
#10 = Utf8 Ljava/lang/Class<Ljava/lang/Void;>;
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 <clinit>
#16 = Utf8 SourceFile
#17 = Utf8 Void.java
#18 = NameAndType #11:#12 // "<init>":()V
#19 = Utf8 void
#20 = Class #25 // java/lang/Class
#21 = NameAndType #26:#27 // getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
#22 = NameAndType #7:#8 // TYPE:Ljava/lang/Class;
#23 = Utf8 java/lang/Void
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/Class
#26 = Utf8 getPrimitiveClass
#27 = Utf8 (Ljava/lang/String;)Ljava/lang/Class;
{
public static final java.lang.Class<java.lang.Void> TYPE;
descriptor: Ljava/lang/Class;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Signature: #10 // Ljava/lang/Class<Ljava/lang/Void;>;
private java.lang.Void();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 49: 0
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #2 // String void
2: invokestatic #3 // Method java/lang/Class.getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
5: putstatic #4 // Field TYPE:Ljava/lang/Class;
8: return
LineNumberTable:
line 44: 0
}
SourceFile: "Void.java"
由于这是一项家庭作业,因此 class 的特定限制很重要。例如,您是否被允许使用库,或者您是否应该编写自己的 class 文件解析器?如果是后者,那么你只需要阅读JVM规范并为其编写解析器即可。
假设您可以使用库,我建议您使用 Objectweb ASM。这将使您不必处理 class 文件格式的底层细节,也不必编写解析器。
查看ClassReader.java,字节码的大小没有直接暴露给客户端代码。但是,readLabel
总是在 readCode
的开头用 codeLength + 1
调用。因此,subclassClassReader
,overridereadLabel
,就可以得到每个方法的字节码长度
您还需要创建一个 MethodVistor
并覆盖 visitMethodInsn
以获取作业后面部分所需的调用指令。
我想知道如何在 class 文件中获取所有方法的列表以及每个方法的字节数。
例如:
我想要一个主要的源代码,它可以通过 cmd 行参数解析少数 .class 文件,并获取每个 classes.
的上述详细信息 javac myapp classFile1.class classFile2.class ...
请注意:我知道方法列表可以通过 javap className.class
最简单的解决方案是 运行 javap
javap -c -v -p -cp . classFile1
这将转储出所有方法和带有方法长度的字节码。
例如
$ javap -c -v -p -cp . java.lang.Void
Classfile jar:file:/opt/jdk1.8.0_51/jre/lib/rt.jar!/java/lang/Void.class
Last modified 08-Jun-2015; size 454 bytes
MD5 checksum 8a3bdf282569bff4cd7c5fc24cbaee83
Compiled from "Void.java"
public final class java.lang.Void
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
#1 = Methodref #6.#18 // java/lang/Object."<init>":()V
#2 = String #19 // void
#3 = Methodref #20.#21 // java/lang/Class.getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
#4 = Fieldref #5.#22 // java/lang/Void.TYPE:Ljava/lang/Class;
#5 = Class #23 // java/lang/Void
#6 = Class #24 // java/lang/Object
#7 = Utf8 TYPE
#8 = Utf8 Ljava/lang/Class;
#9 = Utf8 Signature
#10 = Utf8 Ljava/lang/Class<Ljava/lang/Void;>;
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 <clinit>
#16 = Utf8 SourceFile
#17 = Utf8 Void.java
#18 = NameAndType #11:#12 // "<init>":()V
#19 = Utf8 void
#20 = Class #25 // java/lang/Class
#21 = NameAndType #26:#27 // getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
#22 = NameAndType #7:#8 // TYPE:Ljava/lang/Class;
#23 = Utf8 java/lang/Void
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/Class
#26 = Utf8 getPrimitiveClass
#27 = Utf8 (Ljava/lang/String;)Ljava/lang/Class;
{
public static final java.lang.Class<java.lang.Void> TYPE;
descriptor: Ljava/lang/Class;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Signature: #10 // Ljava/lang/Class<Ljava/lang/Void;>;
private java.lang.Void();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 49: 0
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #2 // String void
2: invokestatic #3 // Method java/lang/Class.getPrimitiveClass:(Ljava/lang/String;)Ljava/lang/Class;
5: putstatic #4 // Field TYPE:Ljava/lang/Class;
8: return
LineNumberTable:
line 44: 0
}
SourceFile: "Void.java"
由于这是一项家庭作业,因此 class 的特定限制很重要。例如,您是否被允许使用库,或者您是否应该编写自己的 class 文件解析器?如果是后者,那么你只需要阅读JVM规范并为其编写解析器即可。
假设您可以使用库,我建议您使用 Objectweb ASM。这将使您不必处理 class 文件格式的底层细节,也不必编写解析器。
查看ClassReader.java,字节码的大小没有直接暴露给客户端代码。但是,readLabel
总是在 readCode
的开头用 codeLength + 1
调用。因此,subclassClassReader
,overridereadLabel
,就可以得到每个方法的字节码长度
您还需要创建一个 MethodVistor
并覆盖 visitMethodInsn
以获取作业后面部分所需的调用指令。