使用javap指令解析Class文件

使用javap指令解析Class文件,第1张

使用javap指令解析Class文件 接卸字节码的作用

通过反编译生成的字节码文件,我们可以深入的了解Java代码的工作机制。但是,自己分析类文件结构太麻烦了!除了使用第三方的jclasslib工具之外,oracle官方也提供了工具:javap。

javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区、局部变量表、异常表和代码行偏移量映射表、常量池等信息。

通过局部变量表,我们可以产看局部变量的作用域范围、所在槽位等信息,甚至可以看到槽位复用等信息。

javac -g *** 作

解析字节码文件得到的信息中,有些信息(如局部变量表、指令和代码行偏移量映射表、常量池中方法的参数名称等等)需要在使用javac编译成class文件时,指定参数才能输出。

比如,直接javac xx.java,就不会生成对应的局部变量表等信息,如果你使用javac -g xx.java就可以生成所有相关信息了。如果你使用的eclipse或者IDEA,则默认情况下,eclipse、IDEA在编译时会帮你生成局部变量表、指令和代码行偏移量映射表等信息。

javap的用法

javap的用法格式:

javap

其中,classes就是要反编译的class文件。
在命令行中直接输入javap或javap -help可以看到javap的options选项:

Usage: javap  
where possible options include:
  -help  --help  -?        Print this usage message
  -version                 Version information
  -v  -verbose             Print additional information
  -l                       Print line number and local variable tables
  -public                  Show only public classes and members
  -protected               Show protected/public classes and members
  -package                 Show package/protected/public classes
                           and members (default)
  -p  -private             Show all classes and members
  -c                       Disassemble the code
  -s                       Print internal type signatures
  -sysinfo                 Show system info (path, size, date, MD5 hash)
                           of class being processed
  -constants               Show final constants
  -classpath         Specify where to find user class files
  -cp                Specify where to find user class files
  -bootclasspath     Override location of bootstrap class files
使用举例

1.代码

package com.example.jvm;

public class SeniorDemo {

    private int num = 1;
    public final String info = "hello world";
    boolean[] counts;

    public SeniorDemo() {

    }

    public SeniorDemo(int count) {
        this.counts = new boolean[count];
    }

    public String getInfo() {
        return info;
    }

    public void addNum(int n) {
        num += n;
        System.out.println(num);
    }
}
  1. javap -v SeniorDemo.class
Classfile /home/mall/work/gitrepository/jvm/out/production/jvm/SeniorDemo.class
  Last modified Nov 11, 2021; size 852 bytes
  MD5 checksum 0d32355daa6291e418aba33a4302a55d
  Compiled from "SeniorDemo.java"
public class SeniorDemo  // 类名称
  minor version: 0
  major version: 52    // 主版本号和副版本号组合,得出编译该文件的jdk版本
  flags: ACC_PUBLIC, ACC_SUPER // 方法标识
#####################################常量池开始########################################
Constant pool: 
   #1 = Methodref          #9.#32         // java/lang/Object."":()V
   #2 = Fieldref           #6.#33         // SeniorDemo.num:I
   #3 = String             #34            // hello world
   #4 = Fieldref           #6.#35         // SeniorDemo.info:Ljava/lang/String;
   #5 = Fieldref           #6.#36         // SeniorDemo.counts:[Z
   #6 = Class              #37            // SeniorDemo
   #7 = Fieldref           #38.#39        // java/lang/System.out:Ljava/io/PrintStream;
   #8 = Methodref          #40.#41        // java/io/PrintStream.println:(I)V
   #9 = Class              #42            // java/lang/Object
  #10 = Utf8               num
  #11 = Utf8               I
  #12 = Utf8               info
  #13 = Utf8               Ljava/lang/String;
  #14 = Utf8               ConstantValue
  #15 = Utf8               counts
  #16 = Utf8               [Z
  #17 = Utf8               
  #18 = Utf8               ()V
  #19 = Utf8               Code
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               LSeniorDemo;
  #24 = Utf8               (I)V
  #25 = Utf8               count
  #26 = Utf8               getInfo
  #27 = Utf8               ()Ljava/lang/String;
  #28 = Utf8               addNum
  #29 = Utf8               n
  #30 = Utf8               SourceFile
  #31 = Utf8               SeniorDemo.java
  #32 = NameAndType        #17:#18        // "":()V
  #33 = NameAndType        #10:#11        // num:I
  #34 = Utf8               hello world
  #35 = NameAndType        #12:#13        // info:Ljava/lang/String;
  #36 = NameAndType        #15:#16        // counts:[Z
  #37 = Utf8               SeniorDemo
  #38 = Class              #43            // java/lang/System
  #39 = NameAndType        #44:#45        // out:Ljava/io/PrintStream;
  #40 = Class              #46            // java/io/PrintStream
  #41 = NameAndType        #47:#24        // println:(I)V
  #42 = Utf8               java/lang/Object
  #43 = Utf8               java/lang/System
  #44 = Utf8               out
  #45 = Utf8               Ljava/io/PrintStream;
  #46 = Utf8               java/io/PrintStream
  #47 = Utf8               println
#####################################常量池结束########################################
#####################################字段表开始########################################
{
  public final java.lang.String info;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_FINAL
    ConstantValue: String hello world

  boolean[] counts;
    descriptor: [Z
    flags:
#####################################字段表结束########################################

#####################################方法表开始########################################
  public SeniorDemo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1 //  *** 作数栈长度,局部变量表长度,参数个数
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field num:I
         9: aload_0
        10: ldc           #3                  // String hello world
        12: putfield      #4                  // Field info:Ljava/lang/String;
        15: return
      LineNumberTable:  // 行号表,代码行号与上面的code中的行号的对应
        line 7: 0  
        line 3: 4
        line 4: 9
        line 9: 15
      LocalVariableTable:  // 局部变量表,start标识局部变量的开始作用域,与code中的相对于
        Start  Length  Slot  Name   Signature
            0      16     0  this   LSeniorDemo; // 表明了作用域,变量名称,变量类型,也能看出槽位有没有被覆用的情况

  public SeniorDemo(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field num:I
         9: aload_0
        10: ldc           #3                  // String hello world
        12: putfield      #4                  // Field info:Ljava/lang/String;
        15: aload_0
        16: iload_1
        17: newarray       boolean
        19: putfield      #5                  // Field counts:[Z
        22: return
      LineNumberTable:
        line 11: 0
        line 3: 4
        line 4: 9
        line 12: 15
        line 13: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0  this   LSeniorDemo;
            0      23     1 count   I

  public java.lang.String getInfo();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: ldc           #3                  // String hello world
         2: areturn
      LineNumberTable:
        line 16: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       3     0  this   LSeniorDemo;

  public void addNum(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=2
         0: aload_0
         1: dup
         2: getfield      #2                  // Field num:I
         5: iload_1
         6: iadd
         7: putfield      #2                  // Field num:I
        10: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: aload_0
        14: getfield      #2                  // Field num:I
        17: invokevirtual #8                  // Method java/io/PrintStream.println:(I)V
        20: return
      LineNumberTable:
        line 20: 0
        line 21: 10
        line 22: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      21     0  this   LSeniorDemo;
            0      21     1     n   I
#####################################方法表结束########################################
}
#####################################属性开始########################################
SourceFile: "SeniorDemo.java"  // 表明类源文件的名称
#####################################属性结束########################################
总结
  1. 通过javap命令可以查看一共java类反汇编得到的Class文件版本号、常量池、访问标识、变量表、指令代码行号表等信息。不显式类索引、父类索引、接口类索引集合、()、等结构。
  2. 通过对前面例子代码反汇编文件的简单分析,可以发现,一个方法的执行通常会涉及下面几块内存的 *** 作:
    1. java栈中,局部变量表、 *** 作数栈
    2. java堆中,通过对象的地址引用去 *** 作
    3. 常量池
    4. 其他如帧数据区、方法区的剩余部分等情况。
  3. 平时,我们比较关注的是java类中每个方法的反汇编中的指令 *** 作过程,这些指令都是顺序执行的,可以参考官方文档查看每个指令的含义。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5437738.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-11
下一篇 2022-12-11

发表评论

登录后才能评论

评论列表(0条)

保存