Java # 类加载子系统
一、概述
1、 类加载器子系统负责从文件系统或者网络中加载.Class文件
2、classloader只负责类的加载,至于他是否能够运行由执行引擎来决定
3、加载的类的信息会存放在方法区(元空间)中
二、加载过程
1、加载阶段
1、通过一个类的全限定名来获得该类的二进制字节流
2、将该字节流所代表的静态存储结构转化为方法区的运行时数据结构
3、在内存中生成一个java.lang.Class对象,作为方法区对这个类的各种数据的访问入口
2、链接阶段
- 验证:验证字节码文件是否合法:
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
- 准备:
- 为类变量分配内存并进行初始化,此时初始化的为零值
- 对于final修饰的类变量,在编译阶段就已经完成了内存的分配,此时会对该变量进行初始化
- 这里并不会为实例变量进行初始化,类变量会分配在方法区中,而实例变量会随着对象一起分配到堆中
- 解析:将常量池中符号引用转换为直接引用
3、初始化阶段
- 此阶段会按顺序收集静态变量与静态代码块中的内容到<clinit>()方法中进行类变量的初始化
- 若该类有父类,会保证该类父类的<clinit>()先执行
- 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁
三、类加载器
- 引导类加载器(Bootstrap_ClassLoader)
- 由C/C++编写,并嵌入在JVM中
- 该类没有父类加载器
- 该类用于加载java的核心类库
- 扩展类加载器(Extension_ClassLoader)
- 该类派生于ClassLoader(是一个抽象类)
- 该类用于加载java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre/lib/ext子目录下加载类库
- 系统类加载器(APPClassLoader)
- 派生于ClassLoader
- 该类用于加载用户自定义类
- 自定义类加载器
四、其他
一、如何判断两个class对象是否相同
- 类的完整类名必须一致,包括包名
- 加载这个类的类加载器必须相同
二、对类加载器的引用
(1)JVM必须知道一个类是由启动类加载器加载的,还是由用户类加载器加载的。
(2)如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。
(3)类的主动、被动使用(是否会导致类加载中的初始化操作)
- 主动使用会导致类的初始化
- 创建类的实例
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(如:class.forName("com.xh.Test"))
- 初始化一个类的子类
- JVM启动时被标明为子类的类
- JDK7开始提供的动态语言支持:java.lang.invoke.MethodHandle实力的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化
- 除了上面的7种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化。
五、双亲委派机制
一、过程
当类加载器接受到一个类加载请求时,并不会直接对该类进行加载,而是会将该请求委派给上一级的加载器。
向上逐层委派到引导类加载器后,由引导类加载器判断自己是否有权限加载该类,有则加载后直接返回,没有则交付给下一层扩展类加载器,扩展类加载器查看自己是否有权限加载该类,有则直接加载后返回,没有则向下继续交付给系统类加载器处理
二、优点
1、保证每个类只被加载一次
2、保护java的核心代码