写在前面:
关于字节码,就是***.java文件经过javac编译成***.class文件中的内容,但是都是二进制,经过反编译后才能看到其中内容。
关于查阅字节码的作用,就是知道.class文件经过classloader加载进内存后发生了什么。
可以用来解释一些平时不会思考到的问题,
比如,finally块中的内容为什么一定会被执行? try语句包裹内容为什么尽量要少?
为什么只要其他类用不到的方法尽量都要是private?各种语法糖是怎么实现的?静态代码块和静态变量初始化的先后顺序?
for循环、while循环的区别在哪等等。。。。
javap 、 asm 、jclasslib这仨,感觉学习要从javap学起,使用的话用jclasslib,asm这个不很熟,但是对着原始代码看很方便。
正文
1. javap
jvm自带的命令,javac是编译,javap是反编译,如图javac 接javap可在命令行看到反编译的字节码内容,注意javac -g 没有-g的话反编译回来各个方法内没有localVariablesTable。
特点:使用原生命令,多个追加参数,初学容易但是查看麻烦,多个版本比对的话还要写个小脚本输出保存到本地。
D:\JavaProject\concurrent\src\main\java\com\htyl\t1>javac -g Demo01.java
D:\JavaProject\concurrent\src\main\java\com\htyl\t1>javap -v Demo01.class
Classfile /D:/JavaProject/concurrent/src/main/java/com/htyl/t1/Demo01.class
Last modified 2021-3-1; size 1003 bytes
MD5 checksum 42e076da2916767b6c072c3f54b22faf
Compiled from "Demo01.java"
public class com.htyl.t1.Demo01
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #16.#36 // java/lang/Object."<init>":()V
#2 = String #37 // a
{
public com.htyl.t1.Demo01();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: ldc #2 // String a
6: astore_1
7: ldc #3 // String b
9: astore_1
10: ldc #4 // String c
12: astore_1
13: return
LineNumberTable:
line 25: 0
line 24: 4
line 26: 7
line 25: 10
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lcom/htyl/t1/Demo01;
13 1 1 c Ljava/lang/String;
=======================================
2. jclasslib
安装: idea -》settings-》plugins-》local或者repository里搜索 jclasslib-》install 然后restart就行了
使用:菜单栏view -》
这个是对字节码比较完整的换皮了,在有点字节码基础以后,可以很方便查找想要的内容
========================================
3. asm
安装:asm插件全称asm bytecode outline,idea -》settings-》plugins-》local或者repository里搜索asm-》install 然后restart就行了,idea2017要装带2017后缀的
使用:项目目录选中.java类文件,右键-》show bytecode outline,右侧就弹出了asm插件界面
这个好像有挺多别的作用,只用来看字节码的话体验不是很好,不是很明显对应了字节码中的结构,异常表槽位等等也不好看。
但有个明显优点,可以看到 开发中每行代码对应的一组jvm指令,可以避免代码太多捋不清走到哪了