JVM类加载过程
类加载流程图:
- 加载:将classpath、jar包中的使用到的class二进制字节码读进来,在JVM内存中生成java.lang.Class对象放入元空间(Metaspace)。
- 验证:验证class文件的二进制字节流中是否符合java虚拟机规范的全部要求。
- 准备:赋值的一个操作。将类的变量进行赋初始值(int 默认赋值为0,long 0L,引用类型赋值为null
,常量赋常量值)。 - 解析:jvm将常量池里面的符号引用翻译为直接引用。
- 初始化:类的初始化。new 对象时,给类变量(静态变量)赋定义的值。执行程序中的静态代码块。
- 使用:运行。
- 卸载:
- 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例;
- 加载该类的ClassLoader已经被GC;
- 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法;
类的初始化顺序
-
正常类
- 静态变量,静态代码块->new 对象时,非静态变量,非静态代码块,构造方法。
-
父子类
- 父类:静态变量,静态代码块->子类:静态变量,静态代码块->父类:非静态变量,非静态代码块,构造方法->子类:非静态变量,非静态代码块,构造方法。
类加载时机
- 调用静态方法
- 调用静态变量
- 创建对象时
- 创建子类对象
- 主动加载Class.forname(“包名.类名”).
jvm类加载器(ClassLoad)
- 启动类加载器:bootstrap ClassLoad,使用c++实现,是java虚拟机的一部分。
- 其他类加载器:由java语言实现,独立于虚拟机的外部,继承抽象类:java.lang.ClassLoad双亲委派机制
类加载器收到类加载的请求,首先不会自身去加载它,而是去委派到它的父类加载器去加载,因此所有的类加载请求最终都要传送到最上层的启动类加载器中,只有当最上层的加载器反馈自己无法加载这个加载请求时,下一层类加载器才会尝试自己加载。如果没有任何一个加载器能加载这个加载请求,JVM就会编译报错。
双亲委派模型的好处
- 确保安全,避免java核心类库被修改。
- 避免重复加载。
- 保证类的唯一性。如果有重复的package类,编译会报错。
定义自身的类加载器
- 继承ClassLoader类。
- 重写父类的findClass()方法 ,或者 loadClass() 方法。
- findClass()方法不会打破双亲委派
- loadClass()方法会打破双亲委派