Java虚拟机之字节码查看工具

 

引入

之前已经讲述了如何在 windows 环境通过 命令行的方式编译Java 代码。

此篇文章作为JVM 系列的引入,简要的说明如何在 windows 平台进行 Java 编译后的 class 文件的查看。其实 JDK 中已经内置了这些工具。可以在 %JAVA_HOME%\bin 目录下看到 javap.exe 这个可执行文件。一些其他的工具在该目录下也都能看到,不过不是此处重点,还是言归正传。本文只做基本演示,后面详细介绍字节码时会逐行详细分析。

示例代码

此处就举一个最简单不过的 Java 示例程序,代码如下:

public class Test{

    private int m;

    public int inc(){
        return m + 1;
    }

}

利器 javap

进入命令行,编译完源码后,会看到源码文件旁有个同名的 .class 文件。接着执行如下命令

javap -c Test  (或 javap -c Test.class)

可以看到如下结果:

F:\tmp\jvmTmp>javap -c Test

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int inc();
    Code:
       0: aload_0
       1: getfield      #2                  // Field m:I
       4: iconst_1
       5: iadd
       6: ireturn
}

这只是展示了当前类和方法的信息。如果要查看详细内容包括常量池、行号表、异常表等信息,可以通过如下命令查看:

javap -verbose Test

执行命令结果如下:

F:\tmp\jvmTmp>javap -verbose Test

Classfile /F:/tmp/jvmTmp/Test.class
  Last modified 2018-7-18; size 265 bytes
  MD5 checksum 0d5efc4b65ae7eb6d64f84136ce58ff9
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#16         // Test.m:I
   #3 = Class              #17            // Test
   #4 = Class              #18            // java/lang/Object
   #5 = Utf8               m
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               inc
  #12 = Utf8               ()I
  #13 = Utf8               SourceFile
  #14 = Utf8               Test.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = NameAndType        #5:#6          // m:I
  #17 = Utf8               Test
  #18 = Utf8               java/lang/Object
{
  public Test();
    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 1: 0

  public int inc();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #2             // Field m:I
         4: iconst_1
         5: iadd
         6: ireturn
      LineNumberTable:
        line 6: 0
}
SourceFile: "Test.java"

可以看到多了文件路径、文件校验、上次修改时间、大小、版本信息、常量池等信息。这是展示字节码信息最丰富的命令了。class 文件中的信息几乎都展示出来了。其中第 11 行可以看到 Constant pool 就是常量池的意思,即行号 12 到 29 都是常量池部分。常量池中的常量通常以 #开头接上序号。

#3 = Class              #17            // Test

如上所示就是第三个常量,= 号后面是该常量项的类型,后面 #17,表示指向第 17 个常量,这里不做展开。

更多用法

当然,javap 的用法不知这些,可以通过如下命令查看所有用法:

F:\tmp\jvmTmp>javap -help

用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

大家可以都尝试下,加深印象。

 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YY_xiaozhu/article/details/81592599
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭