JVM类加载机制
类的生命周期:
加载、连接(验证、准备、解析)、初始化、使用、卸载。解析阶段不一定按顺序,它可以在初始化阶段后开始。

类加载的过程:
- 加载:根据查找路径找到相应的class文件然后导入
- 验证:检查加载的class文件的正确性
- 准备:给类中的静态变量分配内存空间
- 解析:虚拟机常量池内的符号引用替换为直接引用(地址引用)
- 初始化:对静态变量和静态代码块进行初始化
初始化顺序:
- 父类静态成员和静态块、子类静态成员和静态块
- 父类实例变量和非静态块,父类构造函数
- 子类实例变量和非静态块,子类构造函数
类的初始化触发情况:
- new对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射,Class.forName
- 初始化子类,其父类也会被初始化
- 虚拟机启动时被标明为启动的类
类加载器:对任意一个类,都需要由加载它的类加载器和类本身一同确立在JVM中的唯一性。每个类加载器都有独立的类名称空间。类加载器根据指定全限定名将class文件加载到JVM内存,然后转化为class对象
分类:
- 启动类加载器(Bootstrap ClassLoader),加载JAVA安装目录下lib目录中的核心类库,或者被-Xbootclasspah参数锁指定路径中并且被jvm识别的类库
- 扩展类加载器(Ext ClassLoader),加载JAVA安装目录下\lib\ext目录或Java.ext.dirs系统变量指定路径中的所有类库
- 应用程序类加载器(Application ClassLoader),加载ClassPath环境变量指定的路径中的类,可以直接使用该类加载器,默认使用
- 自定义类加载器,根据需求自定义加载
类加载机制:
- 全盘负责,负责加载某个Class时,该Class所依赖和引用的其他Class也该由此类加载器载入,除非显式使用另一个来载入
- 父类委托,先让父类加载器试图加载该类,无法加载时才尝试从自己的类路径中加载类
- 缓存机制,所有加载过的class会被缓存,程序需要某个class时,类加载器先从缓存区寻找,缓存不存在,系统才会读取该类对应的二进制数据,并转换为class对象存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
类加载方式:
- 命令行启动应用时JVM初始化加载
- Class.forName加载
- ClassLoader.loadClass加载
双亲委派:
- 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。所有的类加载请求都会被传递到启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
- AppClassLoader加载一个class,会先委派给ExtClassLoader,然后ExtClassLoader会委派给启动类加载器,如果启动类加载器加载失败会使用ExtClassLoader去加载,加载失败会用AppClassLoader加载,如果还加载失败就抛出异常ClassNoFoundException。
- 自定义类加载器:
- 当网络传输加密后的java类的字节码,我们需要自定义类加载器去取解码。继承ClassLoader类并重写findClass方法。最好不要重写loadClass方法,容易破坏双亲委派模式。
- 为何类加载要父类委托:
- 每个层级的类加载器各司其职,而且不会重复加载一个类。如果两个不同层级的累加器都去尝试加载某个类,没有双亲委派两个类加载器就可以加载同一个类,造成类的重复加载。
本文来自博客园,作者:难得,转载请注明原文链接:https://www.cnblogs.com/zhangbLearn/p/18829096

浙公网安备 33010602011771号