以上便是类加载全过程(全文结束)
下面我们拆分一下 看看每一个步骤都做了些什么
* 加载(加载阶段主要做了三件事)
1.通过一个类的全限定名来获取定义此类的二进制流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据访问入口
* 验证(确保Class文件符合JVM规范,保证运行后不会危害到虚拟机)
1.文件格式校验
是否以魔数开头(0xCAFEBABE开头),常量池是否有不被支持的常量类型等
2.元数据验证
这个类是否有父类,这个类的父类是否继承了不允许被继承的类(被final修饰)等类的编写规范
3.字节码验证
校验类的方法体,如定义了个int类型的数,使用时确按照long来载入到本地变量表中
4.符号引用验证
* 准备
正式为类中定义的静态变量分配内存并设置类变量初始值的阶段
* 解析(解析阶段是Java虚拟机将符号引用替换为直接引用的过程)
1.类或接口解析
2.字段解析
3.方法解析
简单描述 就是把符号占用都直接替换成内存中真正的指针引用了
* 初始化
就是执行类构造器<clinit>()方法的过程,而且有父类的先执行父类的<clinit>
双亲委派模型
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应该有自己的父类加载器
工作过程
如果一个类加载器收到了类的加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父加载器去完成,
每一个层次的类加载器都是如此, 因此所有的加载最终都应该传送到最顶层的情动类加载器中,
只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会自己去加载
原因&好处
有了一种优先级的概念,例如有一个类 不管我用哪个类加载器去加载,最后都会用最顶端的类加载器去加载,保证了各种类加载环境中都能够使用同一个类,保证了Java的安全及稳定性
题外话:
3次破坏双亲委派模型的情景
tomcat的类加载器如何破坏的双亲委派