1、类加载时机
虚拟机严格规定,在以下四种情况下,必须立即进行对类的初始化。
(1)使用new关键字实例化类的对象、读取或设置类的静态字段(final修饰的除外)、调用类的静态方法。
(2)对类进行反射调用的时候。
(3)虚拟机启动时,先初始化用户指定的要执行的主类。
(4)初始化类是,率先初始化此类的父类。
除此之外,所有引用类的方式都不会触发类的初始化(被动引用)
(1)通过子类引用父类的静态字段
(2)通过数组定义引用类 ex:Object obj[] = new Object[10]
(3)常量在编译期间进入常量池,引用此常量不会触发类的初始化。(被static修饰的常量编译期间进入常量池)
2、类加载过程
加载
获取定义此类的二进制字节流
将其转换为方法区的运行时数据结构
在堆中生成Class对象作为这些数据能访问的入口
验证
文件格式验证
元数据验证
字节码验证
符号引用验证
准备:为类变量分配内存,设置类变量初始值。(仅包括statis变量 int num=123,则此阶段赋值0,在类的初始化时赋值为123 static final num=123,则此阶段赋值123)
解析:将常量池内的符号引用转化为直接引用。
类、接口的解析
字段的解析
类方法解析
接口方法解析
初始化:真正开始执行java代码(也就是编译之后的java字节码)
3、类加载器:获取类的二进制字节流代码模块叫做类加载器
类加载器的双亲委派模型:启动类加载器----扩展类加载器----应用程序类加载器----自定义类加载器。
每一个下层类加载器必须有一个父类加载器。在加载类的时候,首先请求父类加载器去加载。如果父类加载器无法加载此类,则由子类完成加载。
双亲委派模型的破坏:(1)在jdk1.2之前已经存在ClassLoader。用户继承此类唯一目的就是重写loadClass方法。在1.2之后,不提倡重写此方法,而是将加载逻辑写入findClass中。
(2)线程上下文类加载器,如果创建线城时未设置,将从父线程中继承一个,如果应用在全局范围内没设置过,则为应用程序类加载器。有了此类加载器,父类加载器可以去请求子类加载器加载类 ex:JDBC JNDI等。
(3)OSGI实现模块化热部署的关键是他自定义类加载器实现机制。每个应用程序模块都有一个类加载器,当需要换模块是,就将模块以及他的类加载器一块换掉来实现代码的热替换。