• 实践详解javap反编译类文件命令参数


    1 缘起

    最近在补充JVM相关知识,开始学着看Java字节码反编译结果,
    对于目前的我而言,只是单纯地补充知识,没有实际的应用启发,
    不过,还是要丰富自己的底层知识,
    现整理学习过程的测试文档,分享如下,
    帮助读者可以快速掌握反编译Java类,查看相关字节码的汇编信息。

    2 javap

    JDK8的javap官网文档地址:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javap.html

    2.1 简介

    • javap命令反汇编一个或多个class文件。输出依赖使用的参数,若不使用参数,直接使用javap命令会打印protected和public限定的类属性和方法。
    • javap命令不支持多版本jar。通过类路径形式使用javap命令只能查看当前jar文件的类文件反编译结果,通过URL形式使用javap命令只能查看指定版本类文件的反编译结果。
    • javap命令直接将结果打印到控制台。

    2.2 查看javap参数

    通过javap -help即可查看javap的参数,
    Windows10中文平台会直接给出中文描述,
    结果如下图所示。

    javap -h
    
    • 1

    由图可知,JDK版本为1.8.0_291,支持invokedynamic,运行时解析调用方法。
    在这里插入图片描述

    3 Code实战

    3.1 原始类

    这里先给出完整的原始类:ByteCodeTest.java,为后面生成字节码及反编译做准备,
    其中,方法调用给出了5种,分别对应如下反编译标识:

    • 构造器方法(invokespecial)
    • 静态方法(invokestatic)
    • 接口方法(invokeinterface)
    • 虚方法(invokevirtual)
    • 动态方法(invokedynamic)
      在代码中在对应的位置已给出注释,源码如下:
    package com.monkey.java_study.clzz;
    
    import com.monkey.java_study.common.entity.UserEntity;
    import com.monkey.java_study.proxy.jdk_proxy.IUserService;
    import com.monkey.java_study.proxy.jdk_proxy.impl.UserServiceImpl;
    
    import java.util.List;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    /**
     * 字节码反编译测试.
     *
     * @author xindaqi
     * @since 2022-08-11 10:48
     */
    public class ByteCodeTest {
    
        public static final String TEST_NAME = "hello world!";
    
        private void test() {
            System.out.println(">>>>>>>>I am test method in current class");
        }
    
        public static void main(String[] args) {
    
            ByteCodeTest byteCodeTest = new ByteCodeTest();
    
            // invokespecial:调用当前类方法
            byteCodeTest.test();
    
            String var1 = "a";
            String var2 = "b";
            UserEntity userEntity = new UserEntity();
    
            // invokevirtual:调用其他类的方法
            userEntity.getNickname();
    
            IUserService userService = new UserServiceImpl();
            // invokeinterface
            userService.add();
    
            List<String> var4 = Stream.of("a", "b", "c").collect(Collectors.toList());
    
            // invokedynamic:运行时解析,调用方法,
            // invokeinterface:forEach为接口方法
            var4.forEach(s -> {
                if ("a".equals(s)) {
                    // invokestatic:System中out为static方法
                    System.out.println(">>>>>>>>I am " + s);
                }
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    3.2 编译为字节码

    这里使用集成开发环境IDEA,通过build项目将ByteCodeTest.java编译为字节码,
    操作方式如下图所示:
    在这里插入图片描述

    存储在target文件夹下,具体的位置:D:/java-basic-with-maven/target/classes/com/monkey/java_study/clzz/ByteCodeTest.class
    编译后项目目录树如下图所示:
    在这里插入图片描述

    3.3 反编译

    这里使用类文件路径方式反编译,即javap [options] class-file-path
    其中,class-path-file为类文件路径。

    3.3.1 javap -v

    查看附加信息。

    javap -v ByteCodeTest.class
    
    • 1

    结果如下图所示,简单的讲解,最前面的信息有:类文件大小、类文件的MD5、JDK版本等,
    通过-v看到的信息比较完整,但是比较多,通过-c查看相关反编译指令。
    在这里插入图片描述

    3.3.2 javap -l

    输出行号和本地变量表。

    javap -l ByteCodeTest.class
    
    • 1

    首先,可以看到原始代码的行号与字节码表的标识对应关系,如下图所示,
    后面查看字节码序号时可以反查是哪一行的源码。
    在这里插入图片描述
    本地变量签名结果如下图所示。
    在这里插入图片描述

    3.3.3 javap -public

    显示公共类和成员。

    javap -public ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.4 javap -protected

    显示受保护的/公共类和成员

    javap -protected ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.5 javap -package

    显示程序包/受保护的/公共类

    javap -package ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.6 javap -p

    显示所有类和成员

    javap -p ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.7 javap -c

    对代码进行反汇编

    javap -c ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.8 javap -s

    输出内部类型签名。

    javap -s ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.9 javap -sysinfo

    显示正在处理类的系统信息(路径、大小、日期、MD5)

    javap -sysinfo ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    3.3.10 javap -constants

    查看最终常量。

    javap -constants ByteCodeTest.class
    
    • 1

    在这里插入图片描述

    4 小结

    (1)javap命令反汇编一个或多个class文件。输出依赖使用的参数,若不使用参数,直接使用javap命令会打印protected和public限定的类属性和方法。
    (2)javap命令不支持多版本jar。通过类路径形式使用javap命令只能查看当前jar文件的类文件反编译结果,通过URL形式使用javap命令只能查看指定版本类文件的反编译结果。
    (3)javap命令直接将结果打印到控制台。
    (4)常用查看汇编的命令:javap -c。

  • 相关阅读:
    冒烟测试和健全性测试差异点,如何区分冒烟测试和健全性测试
    CMS垃圾回收器介绍
    Git代码仓库管理系统的配置方法之:Gitlab
    程序分析与优化 - 5 指针分析
    大唐杯在仿真时出现的问题,是里面的参数配置有问题吗,还是别的方面出现了问题,求指导
    MySQL表的内外连接
    bash install.sh ********错误
    CREAL访谈:将推出光场验光方案,AR眼镜仍是长期目标
    Windows系统反斜杠(倒斜杠 \ )和 Linux系统正斜杠(斜杠 / )
    XShell使用SSH密钥对连接阿里云ECS
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/126282130