输出所有方法的列表,以及 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 以获取作业后面部分所需的调用指令。