类加载
- 类加载子系统
- 类加载器角色
- 类加载过程
- 加载
- 链接
- 初始化
- 类加载器分类
- 双亲委派机制
- 如何打破双亲委派机制
JVM整体分为五大块:
- 类加载系统
- 运行时数据区
- 执行引擎
- 本地方法接口
- 垃圾回收
类加载子系统
类加载器,通俗来讲就是从硬盘上加载由JDK编译后的字节码文件。classLoader 只负责 class 文件的加载,至于它是否可以运行,则由 Execution Engine 决定。 加载的类信息存放于一块称为方法区
的内存空间。
类加载器角色
类加载过程
加载
Class 只有在必须要使用的时候才会被装载, Java 虚拟机不会无条件地装载 Class 类型。Java 虚拟机规定, 一个类或接口在初次使用前, 必须要进行初始化。这里指的“使用”, 是指主动使用, 主动使用只有下列几种情况:
- 当创建一个类的实例时, 比如使用 new 关键字, 或者通过反射、克隆、反序列化。
- 当调用类的静态方法时, 即当使用了字节码 invokestatic 指令。
- 当使用类或接口的静态字段时(final 常量除外), 比如, 使用 getstatic 或者 putstatic 指令。
- 当使用 java.lang.reflect 包中的方法反射类的方法时。
- 当初始化子类时, 要求先初始化父类。
- 作为启动虚拟机, 含有 main 方法的那个类。
加载类处于类装载的第一个阶段。在加载类时, Java 虚拟机必须完成以下工作:
- 通过类的全名, 获取类的二进制数据流。
- 解析类的二进制数据流为方法区内的数据结构。
- 创建 java.lang.Class 类的实例, 表示该类型。
链接
当类加载到系统后, 就开始连接操作, 验证是连接操作的第一步。它的目的是保证加载的字节码是合法、合理并符合规范的。
初始化
对类中静态成员进行赋值。
类什么时候初始化: new 对象, 使用类的静态成员, 反射动态加载类 Class.forName(), 子类被加载, 只访问了类中某个静态的常量
类加载器分类
站在 JVM 的角度看,类加载器可以分为两种:
- 启动类加载器(引导类加载器), 这部分不是用java语言写的
- 其他类加载器(这部分指的是用java语言写的类加载器)
站在 java 开发人员的角度来看,类加载器就应当划分得更细致一些.自 JDK1.2 以 来 java 一直保持者三层类加载器
- 启动类加载器,负责加载java核心类。
- 扩展类加载器 负责加载\jre\lib\ext目录下的类,包含应用程序类加载器。
- 应用程序类加载器,负责加载自己写的程序中的类。
双亲委派机制
系统中的 ClassLoader 在协同工作时, 默认会使用双亲委托模式。即在类加载的时候, 系统会判断当前类是否己经被加载, 如果已经被加载, 就会直接返回可用的类, 否则就会尝试加载, 在尝试加载时, 会先请求双亲处理。通俗来讲就是:
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请 求委托给父类的加载器去执行。
- 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终 将到达顶层的启动类加载器。
- 如果父类加载器可以完成类的加载任务,就成功返回,倘若父类加载器无法完 成加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
如果均加载失败,就会抛出 ClassNotFoundException 异常。
如何打破双亲委派机制