- 类加载的时机
- 主动引用的场景
- 被动引用
- 类加载的过程
- 加载
- 验证
- 准备
- 解析
- 初始化
- 类加载器
- 双亲委派模型
- 破坏双亲委派机制
- 上下文加载器
- OSGI
- 类加载机制:虚拟机把描述类的对象从class字节码加载到内存并完成校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型
- 生命周期:加载、验证、准备、解析、初始化、使用、卸载
验证、准备、解析三个部分为连接
加载、验证、准备、初始化和卸载五个顺序确定
- 遇到new、getstatic、putstatic或者invokestatic时
- 遇到反射时、使用java.lang.reflect包进行反射调用
- 当初始化一个类时发现父类还没有加载过
- 程序启动时加载main方法的类
- 使用jdk1.7动态语言支持时,如果遇到一个java.lang.invoke.MethodHandle实例最后解析结果为REF_getStatic、REG_putStatic、REF_invokeStatic的方法句柄,且句柄所对应的类没有进行初始化过。
- 通过一个类的全限定名来获取定义此类的二进制字节流
获取二进制流的方式包括:网络获取、数据库、jar包、zip包、其他文件生成等方式获取。 - 将这个字节流所代表的静态存储结构转化为方法区的运行数据结构
- 在内存中生成一个代表这个类的java.lang.Class对象。
非数组类的价值过程就是获取二进制字节流 - 数组类的加载过程,数组类本身不通过类加载器加载,由java虚拟机直接创建。创建一个数组A,若数组类的元素类型是引用类型,则采用类加载过程创建。在创建引用基础类型时,将在加载器的类名称空间上标识数组A。若数组的组件类型不是引用类型,java虚拟机将把数组A标记为与引导类加载器关联。
连接阶段第一步,确保class文件的字节流中包含的信息是否符合当前虚拟机的要求并且不会危害虚拟机自身的安全。
验证阶段只要包括四个阶段:文件格式验证、元数据验证、字节码验证、符号应用验证
- 文件格式验证:是否以魔数cafebaby开头,这一阶段主要目的是保证输入字节流能否正确解析并存储到方法区中。
- 元数据验证:对类的元数据信息进行语义校验,保证不存在不符合java语言规范的元数据信息。
- 字节码验证:通过数据流和控制流分析,确定程序语义是否合法,符合逻辑。对类的方法体进行校验分析保证被校验类的方法在运行时不会做出危害虚拟机安全的事件。
- 符号引用验证:最后一阶段发生在虚拟机将符号引用转化为直接引用的时候。
准备阶段是正式为类变量分配内存并设置类初始值得阶段,这些变量所使用的内存都将在方法区中分配。
解析解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
- 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用的时候可以无歧义的定位到目标
- 直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中。
初始化阶段是执行类构造器方法的过程
方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的。编译器收集的顺序是由语句在源文件中出现的顺序决定。
对于任意一个类,需要由加载它的类加载器和类本身确定在虚拟机中的唯一性。比较两个类是否相等,只有在这两个类是否是同一个类加载器加载的前提。
双亲委派模型在加载一个类时,加载器会先委托父加载,父加载器无法加载则有直接加载器。
启动类加载器(Bootstrap ClassLoader):负责加载javahome/lib下面的类,或者被-Xbootclasspath指定路径
扩展类加载器(Extension ClassLoader):负责加载javahome/lib/ext目录中,或者java.ext.dirs系统变量设置路径
应用程序加载器:负责加载用户类路径上所指定的类库
除了启动类加载器,其他类加载器都有父加载器。
重写loadClass
重写findCalss自定义类加载器
例如容器部署了多个应用,这些应用有很多共用的jar包,如果每个应用都加载一次,为了解决这个问题,采用上下文加载器,通过在java.lang.Thread类中设置setContextClassLoaser。通过上下文加载器去加载,父加载器请求子加载器去加载类。逆向加载。
OSGI通过osgi可以实现热部署,每一个模块都有一个加载器,一个模块为一个bundle,一个bundle只能引用其他模块export的类。



