类加载分为:加载—链接(验证、准备、解析)—初始化—使用----卸载。
加载:通过全限定名加载二进制流、将该流的静态结构转化为方法区运行时数据结构
验证:文件格式验证(魔数、基本数据类型)、元数据验证(是否都继承了Object,非抽象类是否实现了接口中的所有方法)、字节码验证(操作数栈的数据类型与指令代码序列都能配合工作,不会出现在操作数栈中放了int类型的变量,使用时却按照long类型来加载入本地变量、类型转换是有效的)、符号引用验证;
准备:将static类变量赋予默认值、static final 变量 若以字面量赋值 则会直接赋值。
解析:将符号引用转化为直接引用
初始化:编译器生成clinit 方法来对静态代码块进行初始化赋值。
类加载器:不管是不同数据源的字节码文件,均需要类加载器将其加载到虚拟机中,在java 8中定义了多种类加载器,bootStrapClassLoader ExtClassLoader appClassLoader以及用户自己定义的classLoader
1、为什么要定义不同的ClassLoader ?
答:区分同名的类。比如俩个模块使用了不同版本的一个类,那么就可以使用不同的类加载器进行加载,从而使得正常工作。 另外,不同的类加载器相当于不同的命名空间,不同 的类加载器可以定制自己的获取二进制字节码的方式,灵活性更高。
2、破坏双亲委派模型的时机?
第一次 是jdk1.2版本之前,此时还没有双亲委派模型。
第二次是 :由于基本思想是越是基础的类越应该由上层的类加载器来加载,但是由于jdk源码中有许多JNDI 和SPI,其实现代码是由不同厂商实现的,所以这部分代码无法由bootStrapClassLoader 加载,所以只能由appClassLoader来加载。
第三次是:代码热替换 。通过自定义类加载器 来加载修改后的模块。
3、使用自定义类加载器的场景由哪些?
不同版本的jar在不同模块中的使用。
类安全:可以自定义累加载器加载加密后的字节码文件。