Java类加载过程
加载
- 通过类名去查找获取此类的二进制流
查找war、jar、网络中获取...
- 将该类所代表的静态存储结构转化为方法区运行时数据
可反推方法区(持久代)保存了类信息
- 在内存中生成一个代表该类的对象,作为方法区这个类的放问入口。
验证
因为class二进制流可以来源的地方很多,所以需要确保该class文件的字节流中包含的信息复合虚拟机要求,不会伤害虚拟机自身。主要分为4个阶段:
- 文件格式验证:编码、头部
- 元数据验证 :java语义校验
- 这个类是否有父类,是否继承了不能继承的类(final)
- 这个类是否实现了父类的所有抽象方法
- 字节码验证
如检查int中是否存了long的数据、指令会不会跳出方法体以外
- 符号引用验证
主要是在接下来解析时验证,判断引用的对象是否能找到对应的类、是否能运行被访问
准备
为类变量赋初值(注:类变量是被static修饰的变量)
解析
对类、接口、字段、方法进行解析
初始化
程序员通过程序制定主观计划区初始化类变量和其他资源
类加载器
Hotspot从jvm角度讲,只有两种类加载器:
- 启动类加载器:底层c++实现,是虚拟机的一部分
- 其他的类加载齐:java实现,独立于虚拟机外部,全部继承于java.lang.ClassLoader.
双亲委派模型
工程过程
- 一个类加载器收到了类的加载请求,首先检查请求的类是否已经被加载过,如果没有
- 自己先不做加载,而是把这个请求委派给父类加载器
- 父类加载器继续向上抛,只有当父类加载器反馈自己无法完成这个加载请求,子类才会尝试自己加载
原理
// 首先检查请求的类是否已经被加载过
Clas c = findLoadedClass(name);
if(c == null){
try{
if(parent != null ){
c = parent.loadClass(name,false);
}else{
//如果没有父类加载器,则尝试用启动类加载器加载
c = findBootstrapClassOrNull(name);
}
}catch(ClassNotFoundException e){
如果父类抛出改方法,证明父类加载器不能完成加载请求
}
if(c == null){
// 调用本身的findcalss方法加载。
c = findClass(name);
}
}
优点
实现了java类加载的一种带有优先级层次的关系,保证了java程序的稳定运作。