class字节码生成与反编译工具
javac与javap
1 | javac -encoding utf-8 Foo.java |
asmtools
1.准备asmtools.jar
1 | 下载安装ant https://ant.apache.org/bindownload.cgi |
2. 准备文件Foo.java
1 | public class Foo { |
3. javac编译为class
1 | javac Foo.java |
4. 查看class内容
class文件是二进制文件,无法直接查看;需要反编译为jasm或java文件才行
Foo.jasm
1 | $ java -jar asmtools.jar jdis Foo.class |
反编译生成Foo.java http://www.benf.org/other/cfr/
1 | $ java -jar cfr-0.152.jar Foo.class |
5.基于jasm生成class
1 | $ java -jar asmtools.jar jasm Foo.jasm |
5.1 绕过java语言规范,看看boolean类型是啥
1 | 将Foo.jasm第14行iconst_1改为iconst_2 |
5.2 换个写法,把boolean bl改为静态变量
Foo.java
1 | public class Foo { |
将java编译为class后查看jasm
1 | lixl@DESKTOP-0SMOHUS MINGW64 /f/test |
将Foo.jasm中16改为iconst_2;然后编译为class并执行
1 | $ java -jar asmtools.jar jasm Foo.jasm |
将Foo.jasm中16改为iconst_3;然后编译为class并执行
1 | lixl@DESKTOP-0SMOHUS MINGW64 /f/test |
将class反编译为java
1 | $ java -jar cfr-0.152.jar Foo.class |
总结:
1 | 1.boolean只能为true和false,只是java语言规范, |
class加载过程
https://blog.csdn.net/briblue/article/details/54973413
https://gitee.com/lixl/dcevm.git
https://gitee.com/lixl/HotswapAgent.git
step1 加载
就是找class文件的过程
类加载器先判断是否加载过该class;没加载过的再加载
BootClassLoader(根类加载器) –> ExtClassLocadr –> AppClassLoader (父子关系、是组合而非继承)
双亲委派,就是ClassLoader加载类时先让ParentClassLoader尝试加载,ParentClassLoader加载不到时才会尝试加载;
好处是,同一个类(packageName+className相同)不会加载多次;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21https://www.zhihu.com/question/466696410
1.如何自定义类加载器(加解密class)?
2.tomcat如何打破双亲委派?
3.JDBC是否打破双亲委派?
```
## step2 链接
验证-》准备-》解析
验证:class是否符合jvm规范,确定一下是不是随便生成的二进制文件
准备:给静态字段分配内存、虚方法绑定方法表
解析:一般再下一步初始化的时候才做,jvm规范也没要求
## step3 初始化
为标记为常量值的字段赋值,以及执行 < clinit > 方法的过程
1.若直接赋值的静态字段被final修饰、且类型是基本类型或者String,
则会被Java编译器标记为常量值,由jvm直接初始化.
其余类型的初始化都会被置于 <clinit> 中,
jvm通过加锁的方式 来保证 clinit 方法只被执行一次. (线程安全的懒加载单例)
2.哪些做法会执行类的初始化
https://blog.csdn.net/qq_22771739/article/details/86348962
主动触发及被动触发
## 扩展:
初始化类、变量时与jvm内存空间的关系
JVM并不会直接使用.class文件,类加载链接的目的就是在JVM中创建相应的类结构,会存储在元空间(方法区)。