1、类的加载
类的加载是指将类的.class文件读取进内存中,并将其放在JVM运行时数据区的方法区内,然后在堆中创建一个java.lang.Class对象,用于封装类在方法区中的数据结构,同时作为方法区数据的访问入口。
2、类的生命周期
类的生命周期指一个class文件从加载到卸载的整个过程
3、类的加载过程
JVM将类的加载分为三个阶段:装载(Load)、链接(Link)、初始化(Initialize)
3.1 装载:查找并加载类的二进制数据
在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的Java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
3.2 链接:验证、准备、解析验证
校验字节码文件的正确性、安全性,包括四种验证:文件格式验证、元数据的验证、字节码验证、符号引用验证
准备
为类变量(static修饰的字段变量)分配内存并且设置该类变量的初始值,这里不包含final修饰的static,因为final在编译的时候就已经分配了。也不会为实例变量分配初始化,实例变量会随着对象分配到堆内存中。
解析
把常量池中的符号引用转换为直接引用,静态链接过程
3.3 初始化:初始化静态变量,执行静态代码块
3.3.1 类的初始化时机
如果一个类被直接引用,就会触发类的初始化。在Java中,直接引用的情况有:通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法
通过反射执行以上三种行为
初始化子类的时候,会触发父类的初始化
作为程序的入口直接运行时(main方法)
3.3.2 类初始化步骤假如这个类还没有被加载和链接,则程序先加载并连接该类(动态加载:主类在运行过程中如果使用到其他类,会逐步加载这些类 eg:jar包和war包中的类并不是一次性都加载到内存中,而是使用时才加载)
假如该类的直接父类还没有被初始化,则先初始化其直接父类
假如类中有初始化语句,则系统依次执行这些初始化语句
4、类加载后方法区存储内容
类被加载到方法区中后主要包含运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。
类加载器的引用:这个类到类加载器实例的引用
对应class实例的引用:类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。
5、类加载器
类加载过程主要通过类加载器实现,Java中有以下几种类加载器:引导类加载器(Bootstrap ClassLoader)
负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar\charsets.jar等,由C++实现,不是ClassLoader子类,Java程序无法直接引用。
拓展类加载器(Extension ClassLoader)
负责加载支撑JVM运行的位于JRE的lib目录下的ext拓展目录中的类库
应用类加载器(App ClassLoader)
负责加载ClassPath路径下的类包,主要加载开发人员写的类
自定义类加载器(Custom ClassLoader)
负责加载用户自定义路径下的类包
类加载器之间存在父子层级结构:
6、双亲委派机制
6.1 定义
双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的加载路径下找不到指定类时,子类才会尝试自己去加载。
6.2 工作过程当应用程序类加载器收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
如果Bootstrap ClassLoader加载失败(在\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
如果均加载失败,就会抛出ClassNotFoundException异常。
6.3 双亲委托机制实现源码(JDK 1.8)
6.4 双亲委托作用沙箱安全机制:防止核心类库被篡改,自己写的java.lang.String不会被加载。
避免类的重复加载:当父加载器已经加载过该类时,子加载器就没必要重新加载一次,保证被加载类的唯一性。
7、自定义类加载器
8、如何打破双亲委派机制
核心:继承ClassLoader,重写类加载方法,实现加载逻辑,不委托给双亲加载