java类加载过程详解

上传人:hs****ma 文档编号:552576485 上传时间:2023-05-11 格式:DOC 页数:13 大小:69KB
返回 下载 相关 举报
java类加载过程详解_第1页
第1页 / 共13页
java类加载过程详解_第2页
第2页 / 共13页
java类加载过程详解_第3页
第3页 / 共13页
java类加载过程详解_第4页
第4页 / 共13页
java类加载过程详解_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《java类加载过程详解》由会员分享,可在线阅读,更多相关《java类加载过程详解(13页珍藏版)》请在金锄头文库上搜索。

1、类(型)的生命周期-装载、连接、初始化、卸载2009-02-14 13:04:54| 分类:Java |字号 订阅Java 虚拟机通过装载、连接和初始化一个 Java 类型 使该类型可以被正在运行的Java程序所使用。负頁把京垦油中的芍 号引用菇换兀宜播弓I花二注制弔式 的JBi3类型jj A Ja-i齣机彌泾JSVS芙空蕊抠档 式正卿井且星斗山也 嗟拟机梗用,1. 装载装载阶段包括三个基本动作: a) 通过该类型的完全限定名,产生一个代表该类 型的二进制数据流。b) 解析这个二进制数据流为方法区的内部数据 结构(方法区)c)创建一个表示该类型的 java.lang.Class 类的实例(堆上

2、)二进制数据的产生的可能是很多的,比如:从本地系 统装载一个 class 文件、网络下载一个 class 文件等等 有了这些二进制数据之后,java虚拟机就会对这些数 据进行足够的处理,然后它才能创建 java.lang.Class 的 实例对象。装载步骤的最终产品就是这个 Class 类的实例对象,它 成为 Java 程序与内部数据结构之间的接口。要访问关 于该类型的信息,程序就要调用该类型对应的 Class 对应的方法。这样一个过程就是把一个二进制数据解析为方法区中 的内部数据结构、并在堆上建立一个 Class 对象的过 程,称为“创建”类型。2. 连接在类型被装载以后,就准备连接了。连接

3、过程的第一步就是:验证2.1 验证在装载过程中,虚拟机必须解析代表类型的二进制数 据流,并且构造内部数据结构,这时候就必须做一些 特定的检查,以保证解析二进制数据的初始工作不会 导致虚拟机崩溃。比如确保每一个部分在正确的位置 拥有正确的长度,验证文件不是太长或者太短,等等 虽然这些检查在装载期间完成,是在正式连接验证之 前完成,但是它们在逻辑上仍然属于验证阶段。在正式的验证阶段可能需要完成一下检查:检查final的类不能拥有子类检查final的方法不能被覆盖 确保在类型和超类型之间没有不兼容的方法声明检查所有常量池入口相互之间一致检查常量池中所有的特殊字符串 检查字节码完整性上面列出的最复杂的

4、任务就是:字节码完验证。所有 的 Java 需以及都必须设法为它们执行的每一个方法检 查字节码的完整性。2.2 准备在准备阶段,Java虚拟机为类变量分配内存,设置默 认初始值。但在到达初始化之前,类变量都没有被初 始化为真正的初始值(准备阶段不执行 Java 代码)。2.3 解析 解析过程就是在类型的常量池中寻找类、接口、字段 和方法的符号引用,把这些符号引用替换成直接引用 的过程。3. 初始化初始化就是为类变量赋予正确的初始值。3.1 初始化的时机在首次主动使用前初始化在类和接口被装载和连接上,Java虚拟机规范提供了 一定的灵活性。但是它严格地定义了初始化的时机。 所有的 Java 虚拟

5、机实现必须在每个类或接口首次主动使用时初始化。下面6 种情况符合主动使用的要求:当创建某个类的新实例时(new;或者不明确的创建。反射。克隆或者反序列化)调用某个类的静态方法使用某个类或接口的静态字段,或者对该字段赋值 (final 修饰的除外,它被初始化为一个编译时的常量 表达式) 调用 Java API 中的某些反射方法 当初始化某个类的子类时(要求超类也已经初始 化)当虚拟机启动时某个被表明为启动类的类(main()方法那个类)除了上述 6 种情况以外,所有其他使用 Java 类型的方 式都是被动使用。它们都不会导致Java类型的初始化。对于第三点,使用一个非常量的静态字段只有当类或者接

6、口的确使用了这个字段时才是主动使用。比如,类中声明的字段可能会被子类引用;接口中声明的字段可能会被子接口或者实现了这个接口的类引用,对于子类、子接口和实现了接口的类来说,这就 是被动使用使用它们并不会触发它们的初始化。只有当字段的确是被类或者接口声明的时候才是主动 使用。当然,超类和子类的规则对于接口并不适用,一个接 口的初始化不要求它的父接口预先被初始化。只有在 某个接口所声明的非常量字段被使用时,该接口才会 被初始化,而不是因为这个接口的子接口或类要初始 化而被初始化。无论如何,如果一个类型在它的首次使用之前还没有 被装载和连接的话,那它必须不在此时被装载和连 接,这样它才能被初始化。装载

7、、连接可以在更早的 时候进行。3.2 初始化初探为类变量赋予正确的初始值是通过:类变量初始化语句或者静态初始化语句给出的。一个类变量初始化语句是变量声明后面的等号和表达 式:class Example1a / = 3 * (int) (Math.random() * 5.0) is the class variable/ initializerstatic int size = 3 * (int) (Math.random() * 5.0);静态初始化语句是一个以static关键字开头的程序快:class Example1b static int size;/ This is the stat

8、ic initializerstatic size = 3 * (int) (Math.random() * 5.0);所有的类变量初始化语句和类型的静态初始化器都被 Java 编译器收集在一起,放到一个特殊的方法中,称 为 类/接口初始化方法vclinit。初始化接口并不需要初始化它的父接口,因为初始化 接口只需要一步:如果接口存在初始化方法,就执行 那个方法。3.3 vclinit方法不是必须的并非所有的类都需要在它们的 class 文件中拥有一个 clinit方法。只有那些的确需要执行Java代码来赋予 类变量正确初始值的类才会有类初始化方法。以下情 况就不会有clinit方法:类没有声

9、明任何类变量,也没有静态初始化语句。声明了类变量,但是没有明确使用类变量初始化语 句或者静态初始化语句 仅包含静态 final 变量的类变量初始化语句,而且 这些类变量初始化语句采用编译时常量表达式卜面的代码就不会产生clinit方法: class Example1d static final int angle = 35;static final int length = angle * 2;两个常量赋予的初始化,这些表达式是编译时常量。Exampleld类被Java虚拟机装载的时,angle和length 字段并非类变量,它们是常量,不是保存在方法区中Java 虚拟机在使用它们的任何类的常

10、量池或者字节码 流中直接存放的是它们表示的常量的 int 值。因此不 需要clinit方法3.4接口中的vclinit方法所有的接口中声明的隐式公开(public)、静态(static) 和最终(final)字段都必须在字段初始化语句中初始 化。如果接口包含任何不能在编译时被解析成为一个 常量的字段初始化语句,接口就会有一个clinit方法。interface Example1f int ketchup = 5;int mustard = (int) (Math.random() * 5.0);这两个隐式公开的字段只有mustard被clinit方法 初始化了。因为 ketchup 字段被初始

11、化为一个编译时 常量,它被编译器特殊处理了。4.卸载在很多方面,Java虚拟机中类的生命周期和对象的生 命周期很相似。虚拟机创建并初始化对象,使程序能 使用对象,然后在对象变得不再引用后可选地执行垃 圾收集。同样,虚拟机装载、连接并初始化类,使得 程序能使用类,当程序不在引用它们的时候可选地卸 载它们。类的垃圾收集这卸载在 Java 虚拟机中很重要,是因为Java 程序可以在运行时通过用户自定义的类装载器 装载类型来动态扩展程序,所有被装载类型都在方法 区占据内存空间,方法区的不能无限增长,所以得收 集、卸载。判断一个动态装载的类型是否仍然需要的方法就是:如果程序不再引用某类型,那么这个类型就可以被收使用启动类装载器装载的类型永远是可触及的,所以 永远不会被卸载。只有用户定义的类装载器装载的类 型才会变成不可触及的,从而被虚拟机回收。5.总结 类在装载、连接、初始化以后,这就把一个类型二进 制数据解析为方法区中的内部数据结构、并在堆上建 立了一个 Class 对象,类变量也已经正确初始化,这 样就可以随时访问它的静态字段,调用静态方法或者 创建它的实例(创建对象)。当类(型)在变得不可收集以后,就会被虚拟机回收

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 模板/表格 > 财务表格

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号