一、类加载的时机
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。
其中验证、准备、解析3个阶段统称为连接
其中,加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段以后再开始,这是为了支持java语言的运行时绑定(也称为动态绑定或晚期绑定)。
虚拟机规范严格规定了有且只有5中情况立即对类进行“初始化”:
- 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条字节码指令的常见Java代码场景:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候
- 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
- 当初始化一个类的时候,如果发现其法雷还没有进行过初始化,则需要先触发其父类的初始化
- 当虚拟机启动时,用户需要指定一个要执行的朱磊(包含main方法的哪个类),虚拟机会先初始化这个类
- 没理解。。。后面补
二、类加载的过程
2.1 加载
在加载阶段,虚拟机需要完成以下3件事:
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区的这个类的各种数据的访问入口
2.2 验证
是连接阶段的第一步,目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
大致会完成下面4个阶段的验证动作:
- 文件格式验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理
- 元数据验证:对字节码的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求
- 字节码验证:确保程序语义合法、符合逻辑
- 符号引用验证:对类自身以外的信息进行匹配性校验
2.3 准备
为类变量分配内存并设置变量初始值的阶段,这些变量的内存都将在方法区中进行分配。
2.4 解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
2.5 初始化
是类加载过程的最后一步,开始真正执行类中定义的Java程序代码
三、类加载器
3.1 类与类加载器
对于任意一个类,都需要由加载它的类加载器和这个类的本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。
即:比较两个类是否“相等”,只有在这两个类是由同一个类加载器的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。
3.2 双亲委派机制
类加载器分为:
- 启动类加载器
- 扩展类加载器
- 应用程序类加载器
应用程序是由这3中类加载器相互配合进行加载到的,如果有必要,还可以加入自己定义的类加载器。
类加载器的这种层次关系,成为类加载器的双亲委派模型。双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。
双亲委派模型的工作过程:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载
以上均为深入理解Java虚拟机拙劣的摘抄
详细内容第二遍读的时候补充