美文网首页
如何查看字节码

如何查看字节码

作者: 假装门口当前台 | 来源:发表于2022-09-28 10:20 被阅读0次
    1. 把java文件编译生成class文件,
    // 编写HelloByteCode.java
    public class HelloByteCode {
        public static void main(String[] args) {
            HelloByteCode obj = new HelloByteCode();
        }
    }
    
    1. 通过命令行生成class文件
      通过Android Studio idea 查看生成的class文件,由此也可以看出,默认构造函数就在这里生成了
    // HelloByteCode.class
    public class HelloByteCode {
        public HelloByteCode() {
        }
    
        public static void main(String[] var0) {
            new HelloByteCode();
        }
    }
    

    其中javac有很多参数可用,可以通过javac --help查看

    javac --help
    用法: javac <options> <source files>
    其中, 可能的选项包括:
      @<filename>                  从文件读取选项和文件名
      -Akey[=value]                传递给注释处理程序的选项
      --add-modules <模块>(,<模块>)*
            除了初始模块之外要解析的根模块; 如果 <module>
                    为 ALL-MODULE-PATH, 则为模块路径中的所有模块。
      --boot-class-path <path>, -bootclasspath <path>
            覆盖引导类文件的位置
      --class-path <path>, -classpath <path>, -cp <path>
            指定查找用户类文件和注释处理程序的位置
      -d <directory>               指定放置生成的类文件的位置
      -deprecation                 输出使用已过时的 API 的源位置
      --enable-preview             启用预览语言功能。要与 -source 或 --release 一起使用。
      -encoding <encoding>         指定源文件使用的字符编码
      -endorseddirs <dirs>         覆盖签名的标准路径的位置
      -extdirs <dirs>              覆盖所安装扩展的位置
      -g                           生成所有调试信息
      -g:{lines,vars,source}       只生成某些调试信息
      -g:none                      不生成任何调试信息
      -h <directory>               指定放置生成的本机标头文件的位置
      --help, -help, -?            输出此帮助消息
      --help-extra, -X             输出额外选项的帮助
      -implicit:{none,class}       指定是否为隐式引用文件生成类文件
      -J<flag>                     直接将 <标记> 传递给运行时系统
      --limit-modules <模块>(,<模块>)*
            限制可观察模块的领域
      --module <模块>(,<模块>)*, -m <模块>(,<模块>)*
            只编译指定的模块,请检查时间戳
      --module-path <path>, -p <path>
            指定查找应用程序模块的位置
      --module-source-path <module-source-path>
            指定查找多个模块的输入源文件的位置
      --module-version <版本>        指定正在编译的模块版本
      -nowarn                      不生成任何警告
      -parameters                  生成元数据以用于方法参数的反射
      -proc:{none,only}            控制是否执行注释处理和/或编译。
      -processor <class1>[,<class2>,<class3>...]
            要运行的注释处理程序的名称; 绕过默认的搜索进程
      --processor-module-path <path>
            指定查找注释处理程序的模块路径
      --processor-path <path>, -processorpath <path>
            指定查找注释处理程序的位置
      -profile <profile>           请确保使用的 API 在指定的配置文件中可用
      --release <release>          针对特定发行版进行编译。支持的发行版:7, 8, 9, 10, 11, 12
      -s <directory>               指定放置生成的源文件的位置
      --source <release>, -source <release>
            提供与指定发行版的源兼容性。支持的发行版:7, 8, 9, 10, 11, 12
      --source-path <path>, -sourcepath <path>
            指定查找输入源文件的位置
      --system <jdk>|none          覆盖系统模块位置
      --target <release>, -target <release>
            生成针对特定 VM 版本的类文件。支持的版本:7, 8, 9, 10, 11, 12
      --upgrade-module-path <path>
            覆盖可升级模块位置
      -verbose                     输出有关编译器正在执行的操作的消息
      --version, -version          版本信息
      -Werror                      出现警告时终止编译
    

    其中javac -g HelloByteCode.java 可以生成测试信息,大家可以自行尝试

    1. 查看字节码
      通过命令行方式
    javap -c -verbose HelloByteCode.class
    
    javap -c -verbose HelloByteCode.class
    Classfile /Users/xxxDesktop/java/HelloByteCode.class
      Last modified 2022年9月29日; size 288 bytes
      MD5 checksum b572cf2c2ccd067ad41d5c137a875273
      Compiled from "HelloByteCode.java"
    public class HelloByteCode
      minor version: 0
      major version: 56
      flags: (0x0021) ACC_PUBLIC, ACC_SUPER
      this_class: #2                          // HelloByteCode
      super_class: #4                         // java/lang/Object
      interfaces: 0, fields: 0, methods: 2, attributes: 1
    Constant pool:
       #1 = Methodref          #4.#13         // java/lang/Object."<init>":()V
       #2 = Class              #14            // HelloByteCode
       #3 = Methodref          #2.#13         // HelloByteCode."<init>":()V
       #4 = Class              #15            // java/lang/Object
       #5 = Utf8               <init>
       #6 = Utf8               ()V
       #7 = Utf8               Code
       #8 = Utf8               LineNumberTable
       #9 = Utf8               main
      #10 = Utf8               ([Ljava/lang/String;)V
      #11 = Utf8               SourceFile
      #12 = Utf8               HelloByteCode.java
      #13 = NameAndType        #5:#6          // "<init>":()V
      #14 = Utf8               HelloByteCode
      #15 = Utf8               java/lang/Object
    {
      public HelloByteCode();
        descriptor: ()V
        flags: (0x0001) 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 static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: (0x0009) ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=2, args_size=1
             0: new           #2                  // class HelloByteCode
             3: dup
             4: invokespecial #3                  // Method "<init>":()V
             7: astore_1
             8: return
          LineNumberTable:
            line 3: 0
            line 4: 8
    }
    

    如果是带-g测试信息的class文件,效果是如下,多了额外的本地变量信息

     javap -c -verbose HelloByteCode.class
    Classfile /Users/hzhenx/Desktop/java/HelloByteCode.class
      Last modified 2022年9月29日; size 415 bytes
      MD5 checksum 05c705e182f58d3b5aa49c28d9e70d1d
      Compiled from "HelloByteCode.java"
    public class HelloByteCode
      minor version: 0
      major version: 56
      flags: (0x0021) ACC_PUBLIC, ACC_SUPER
      this_class: #2                          // HelloByteCode
      super_class: #4                         // java/lang/Object
      interfaces: 0, fields: 0, methods: 2, attributes: 1
    Constant pool:
       #1 = Methodref          #4.#19         // java/lang/Object."<init>":()V
       #2 = Class              #20            // HelloByteCode
       #3 = Methodref          #2.#19         // HelloByteCode."<init>":()V
       #4 = Class              #21            // java/lang/Object
       #5 = Utf8               <init>
       #6 = Utf8               ()V
       #7 = Utf8               Code
       #8 = Utf8               LineNumberTable
       #9 = Utf8               LocalVariableTable
      #10 = Utf8               this
      #11 = Utf8               LHelloByteCode;
      #12 = Utf8               main
      #13 = Utf8               ([Ljava/lang/String;)V
      #14 = Utf8               args
      #15 = Utf8               [Ljava/lang/String;
      #16 = Utf8               obj
      #17 = Utf8               SourceFile
      #18 = Utf8               HelloByteCode.java
      #19 = NameAndType        #5:#6          // "<init>":()V
      #20 = Utf8               HelloByteCode
      #21 = Utf8               java/lang/Object
    {
      public HelloByteCode();
        descriptor: ()V
        flags: (0x0001) 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
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   LHelloByteCode;
    
      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: (0x0009) ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=2, args_size=1
             0: new           #2                  // class HelloByteCode
             3: dup
             4: invokespecial #3                  // Method "<init>":()V
             7: astore_1
             8: return
          LineNumberTable:
            line 3: 0
            line 4: 8
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  args   [Ljava/lang/String;
                8       1     1   obj   LHelloByteCode;
    }
    SourceFile: "HelloByteCode.java"
    

    其中可以看到多了

     LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  args   [Ljava/lang/String;
                8       1     1   obj   LHelloByteCode;
    

    也可以通过Android Studio 的插件jclasslib可视化去查看

    1. Android Stuido 安装插件


      1. 打开Preferences
      进入Plugins,搜索jclasslib

      然后点击安装,重启ide

    2. 使用jclasslib查看字节码


      IDE打开class文件
      View->Show bytecode
    各种信息直观展示

    至于怎么读懂字节码后面更新

    相关文章

      网友评论

          本文标题:如何查看字节码

          本文链接:https://www.haomeiwen.com/subject/obahartx.html