您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
javap命令介绍及如何通过javap排查问题
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
javap命令介绍及如何通过javap排查问题
自猿其说Tech
2021-12-02
IP归属:未知
43440浏览
计算机编程
### 1 引言 众所周知,Java 虚拟机执行的是class文件格式。一个class文件中包含了Java虚拟机指令(或字节码)以及其它辅助信息。 class文件对于开发者来说,基本无法阅读。所以,我们需要一个工具将class文件转换为开发者易懂的语言,类似于JVM的汇编指令,让我们更好的理解代码在JVM中的执行顺序等,javap就是用来完成这个事情的。 ### 2 Javap命令 #### 2.1 Javap介绍 javap是Jdk中自带的反汇编命令,主要作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息。 这里面有些信息(如本地变量表、指令和代码行偏移量映射表、常量池中方法的参数名称等等)需要在使用javac编译成class文件时,指定参数才能输出,比如,你直接javac target.java,是不会生成对应的局部变量表等信息的,只有使用-g参数后,例如javac -g target.java才可以生成所有相关信息了。如果你使用的idea,则默认情况下,idea在编译时会帮你生成局部变量表、指令和代码行偏移量映射表等信息的。 通过反编译生成的汇编代码,我们可以深入的了解java代码的工作机制。 #### 2.2 javap命令说明 通过命令行输入:javap -help,可以显示javap的使用方法,如下: ``` 用法: 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> 覆盖引导类文件的位置 ``` 如下图所示: ![](//img1.jcloudcs.com/developer.jdcloud.com/7695cfc4-2146-4bd1-aae3-23209afc9a6c20211202152228.png) ### 3 利用javap排查问题 #### 3.1 三目运算引发空指针 前阵儿,有个同学写了下面这段代码 ![](//img1.jcloudcs.com/developer.jdcloud.com/c3b1bec8-3fa7-4e26-8b66-9d3c2e341c1020211202152245.png) 提测后报NPE异常了,于是这位同学问为什么? #### 3.2 问题还原 由于业务代码略显繁琐,我们简化下,上面的三目表达式类似于这样boolean ? a : b,当a为Integer 类型而b为int类型的时候,且a的值为null的时候,会报NPE异常信息,看到这里很多同学可能已经明悟了。 下面,我们还原一下现场,如下图所示: ![](//img1.jcloudcs.com/developer.jdcloud.com/423316b1-24c1-4508-9043-b7a35f9a141d20211202152307.png) 和预期一样,这段代码报NPE了。 #### 3.3 反编译 然后我们通过javap反编译一下这个类 ``` D:\test\src>javap -c -l Test.class Compiled from "Test.java" public class src.Test { public src.Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 public static void main(java.lang.String[]); Code: 0: aconst_null 1: astore_1 2: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 5: aload_1 6: invokevirtual #3 // Method java/lang/Integer.intValue:()I 9: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 12: return LineNumberTable: line 5: 0 line 6: 2 line 7: 12 ``` 实操截图如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/2566ca9f-57ec-4e3a-9b15-278bc6e7b3bf20211202152339.png) 注意红框部分,这句// Method java/lang/Integer.intValue:()I,这个就是问题所在,具体我们下面分析。 #### 3.4 分析总结 为了尽可能准确,我扒了一下java标准官网对于表达式标准的原文说明,贴图如下,供参考: ![](//img1.jcloudcs.com/developer.jdcloud.com/288ec475-e987-4137-b572-84c516b05fd320211202152355.png) 提炼上面信息后,简单说就是:当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。 所以,由于使用了三目运算符,并且第二、第三位操作数分别是基本类型和对象。所以对对象进行拆箱操作,由于该对象为null,在拆箱过程中调用Integer.intValue变成了null.intValue(),所以就报了NPE。 4 参考网址 - Javap官网:https://docs.oracle.com/en/java/javase/17/docs/specs/man/javap.html - Java语言规范运算符:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25 - NPE异常:NullPointerException - 小贴士:自动拆装箱是JDK1.5引入的,由编译器来支持。 ------------ ###### 自猿其说Tech-京东物流技术发展部 ###### 作者:范亮
原创文章,需联系作者,授权转载
上一篇:以产品视角看项目管理
下一篇:不得不说的数据库索引
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号