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 exception
private 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:\code\1.txt

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

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

https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

下面对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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

一个简单的例子教会您使用javap的更多相关文章

  1. 用一个简单的例子来理解python高阶函数

    ============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...

  2. Spring-Context之一:一个简单的例子

    很久之前就想系统的学习和掌握Spring框架,但是拖了很久都没有行动.现在趁着在外出差杂事不多,就花时间来由浅入深的研究下Spring框架.Spring框架这几年来已经发展成为一个巨无霸产品.从最初的 ...

  3. 关于apriori算法的一个简单的例子

    apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...

  4. 扩展Python模块系列(二)----一个简单的例子

    本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...

  5. fitnesse - 一个简单的例子(slim)

    fitnesse - 一个简单的例子(slim) 2017-09-30 目录1 编写测试代码(Fixture code)2 编写wiki page并运行  2.1 新建wikiPage  2.2 运行 ...

  6. Struts2的配置和一个简单的例子

    Struts2的配置和一个简单的例子 笔记仓库:https://github.com/nnngu/LearningNotes 简介 这篇文章主要讲如何在 IntelliJ IDEA 中使用 Strut ...

  7. 一个简单的例子搞懂ES6之Promise

    ES5中实现异步的常见方式不外乎以下几种: 1. 回调函数 2. 事件驱动 2. 自定义事件(根本上原理同事件驱动相同) 而ES6中的Promise的出现就使得异步变得非常简单.promise中的异步 ...

  8. 一个简单的例子了解states

    在大规模的配置管理工作中,我们要编写大量的states.sls文件.top.sls是states系统的入口文件,它负责指定哪些设备调用哪些states.sls文件.statse的默认工作目录是在/sr ...

  9. 跨站脚本功攻击,xss,一个简单的例子让你知道什么是xss攻击

    跨站脚本功攻击,xss,一个简单的例子让你知道什么是xss攻击 一.总结 一句话总结:比如用户留言功能,用户留言中写的是网页可执行代码,例如js代码,然后这段代码在可看到这段留言的不同一户的显示上就会 ...

随机推荐

  1. Numbers Exchange

    题意: Eugeny有n张卡片,他希望和Nikolay交换一些卡片使得他拥有的奇数数字和偶数数字的卡片数目一样,且所有数字都不同. Nikolay有m张卡片,分别写着1到m.问最少交换几次,能够满足要 ...

  2. classpath路径指什么

    一.classpath路径指什么 只知道把配置文件如:mybatis.xml.spring-web.xml.applicationContext.xml等放到src目录(就是存放代码.java文件的目 ...

  3. SSH框架搭建的时候遇到的问题

    1.spring-web.jar包问题:使用user libaries方式,识别不到,于是出现了下面问题 java.lang.ClassNotFoundException: org.springfra ...

  4. C++ 预处理指令 #pragma

    http://www.cnblogs.com/qinfengxiaoyue/archive/2012/06/05/2535524.html

  5. Flutter实战视频-移动电商-51.购物车_Provide中添加商品

    51.购物车_Provide中添加商品 新加provide的cart.dart页面 引入三个文件.开始写provide类.provide需要用with 进行混入 从prefs里面获取到数据,判断有没有 ...

  6. HDU - 4535 ZZULI 1867: 礼上往来【错位排序】

    1867: 礼上往来 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 216  Solved: 65 SubmitStatusWeb Board Desc ...

  7. 网络编程-TCP连接-readLine

    Server: package com.net.tcp; import java.io.BufferedReader; import java.io.IOException; import java. ...

  8. HDU1080 【LCS变形】

    题意: 给你每种字符匹配的权值大小,给你两个串,长度小的串可以在小串里面添加空格和大串匹配,问你一个最大匹配权值. 思路: 有点类似于LCS吧,我们在求两个串的LCS的时候,不行的就扔掉了,在这里就是 ...

  9. 剑指OFFER之最大子向量和(连续子数组的最大和)(九度OJ1372)

    题目描述: HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天JOBDU测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但 ...

  10. Node.js 使用Stream的pipe(管道)方法实现文件复制

    Stream模块有一个pipe方法,可以将两个流串起来,实现所有的数据自动从Readable流进入Writable流 "use strict"; const fs = requir ...