博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个简单的例子教会您使用javap
阅读量:6505 次
发布时间:2019-06-24

本文共 1994 字,大约阅读时间需要 6 分钟。

javap是JDK自带的工具:

这篇文章使用下面这段简单的Java代码作为例子进行讲解。

class Outer {    Nested nested;    Nested getNested() {        return nested;    }}class Nested {    Inner inner;    Inner getInner() {        return inner;    }}class Inner {    String foo;    String getFoo() {        return foo;    }}public class NullableTest {    public static Outer getInitializedOuter(){        Outer outer = new Outer();        outer.nested = new Nested();        outer.nested.inner = new Inner();        outer.nested.inner.foo = "Jerry";        return outer;    }    /* null pointer exceptionprivate static void way0(){Outer outer = new Outer();System.out.println(outer.nested.inner.foo);}*/    public static void way1(){        Outer outer = getInitializedOuter();        if (outer != null && outer.nested != null && outer.nested.inner != null) {            System.out.println(outer.nested.inner.foo);        }    }    public static void main(String[] args) {        //way0();        way1();    }}

使用下面的命令行对NullableTest进行反编译,以java编译器生成的字节码:

javap -v NullableTest >c:code1.txt

查看方法way1()对应的字节码:

下面这个wiki包含了java字节码里每个指令的具体说明:

下面对NullableTest反编译得到的字节码做一些说明:

0: invokestatic #42 // Method getInitializedOuter:()Ljava8/Outer;

代表静态方法getInitializedOuter的调用, Ljava8/Outer意思是该方法的返回类型是Outer

3: astore_0

将上述静态方法调用返回的outer引用存储到局部变量中,局部变量的id为0.

4: aload_0

因为在我前面的Java源代码中,我将静态方法返回的对象引用同null做了比较,因此使用指令aload_0将存储在代号为0的局部变量中的对象引用重新加载到栈上,此后才能和null做比较。

5: ifnull 41

这就是我在Java源代码里书写的IF分支。如果IF分支里检测的outer引用为null,则直接返回了。体现在字节码就是,如果ifnull为true,则跳转到第41行字节码,即直接返回。

如果ifnull不为true,则继续执行下去。又将outer引用加载到栈上。

从字节码的分析可以观察到一个有趣的现象,再次看看我们的IF语句。

Java编译时,编译器实际将其转换成了下面的写法:

if (outer == null )return;if( outer.nested == null )return;if( outer.nested.inner == null)return;System.out.println(outer.nested.inner.foo);

这个事实可以通过下图得到确认。

javap生成的字节码里的LineNumberTable也很有用。这张表里每行的line后面的数字代表Java源代码的序号,line XX冒号后面的数字代表字节码里每行指令的序号。看看下图中Java源代码和对应的字节指令在LineNumberTable中的映射关系。

LineNumberTable维护了Java源代码同字节指令的映射关系,确保了Java代码调试的顺利进行。

要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

转载地址:http://jbqyo.baihongyu.com/

你可能感兴趣的文章
Lua(Codea) 中 table.insert 越界错误原因分析
查看>>
ELK 5.x日志分析 (二) Elasticserach 5.2 安装
查看>>
一次奇怪的AP注册异常问题处理
查看>>
TableStore: 海量结构化数据分层存储方案
查看>>
Unity 4.x游戏开发技巧集锦(内部资料)
查看>>
自适应网页设计
查看>>
获取BT节点信息bittorrent-discovery
查看>>
Centos 7使用vsftpd搭建FTP服务器
查看>>
linux下SVN不允许空白日志提交
查看>>
第2周第1课
查看>>
山寨c 标准库中的getline 函数
查看>>
shell时间
查看>>
pfSense book之2.4安装指南
查看>>
org.springframework.data.redis 一次连接获取特定key所有k-v(pipeline)
查看>>
[译稿]同步复制提议 2010-09
查看>>
windows 自动化目录大纲(各企业架构不一样,按需选择)
查看>>
我的友情链接
查看>>
【Visual C++】游戏开发笔记十三 游戏输入消息处理(二) 鼠标消息处理
查看>>
我的友情链接
查看>>
Java 使用 Redis
查看>>