一个简单的例子教会您使用javap
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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:
相关文章
- 手把手教你从零写一个简单的 VUE
- 利用angular4和nodejs-express构建一个简单的网站(一)——构建前后端开发环境
- 微信小程序入门之构建一个简单TODOS应用
- dubbo专题」dubbo其实很简单,就是一个远程服务调用的框架(1)
- 一个简单的物料防错DEMO
- 实现一个简单的虚拟demo算法
- SAP UI5函数节流(Throttle)的一个最简单的例子
- 27 行代码开发一个最简单的 SAP ALV 报表试读版
- Java servlet一个最简单的例子
- 使用maven的一个最简单的例子
- 最简单的Docker镜像教程:从头基于空镜像scratch创建一个新的Docker镜像
- 通过一个简单的例子学习Angular Injection Token工作原理
- 通过一个最简单的例子,理解Angular rxjs里的Observable对象的pipe方法
- 怎样使用纯CSS3创建一个简单的五角星图形
- QT实现一个简单的MP3播放器(有资源例子)
- QT实现一个简单的MP3播放器(有资源例子)
- Java产生死锁的一个简单例子
- 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件
- 一步一步写一个简单通用的makefile(一)
- mDNS原理的简单理解——每个进入局域网的主机,如果开启了mDNS服务的话,都会向局域网内的所有主机组播一个消息,我是谁,和我的IP地址是多少。然后其他也有该服务的主机就会响应,也会告诉你,它是谁,它的IP地址是多少
- Net Core 微服务 - 如何在docker容器里运行一个简单的.net core web api 服务
- Spring JDBC 框架一个最简单的Hello World级别的例子