说明
1 类加载(Class Loading)包括加载,验证,准备,解析,和初始化五个部分.
2 这个文档里介绍的是加载,验证和准备
加载
加载(Loading)是类加载(Class Loading)过程中的一个阶段,在加载时,虚拟机完成了三件事情:
(1) 通过类的全额定名来获取定义此类的二进制字节流.
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
(3) 在Java堆里生产一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口.
可以看出来,其实虚拟机规范中这三点要求都不具体.它甚至没有规定类的二进制字节流必须是通过javac编译产生的.正因为虚拟机规范在加载阶段的开发,才造成后面好多举足轻重的Java技术都建立在这个基础上.比如
(1) 从ZIP包获取二进制流,最终产生了jar,ear,war等格式.
(2) 网络中获取,比如Applet应用.
(3) 运行时计算生成,比如java.lang.reflect.Proxy类运行时创建对象.
(4) ….
加载阶段完成以后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区
中,方法区中的数据存储格式由具体的虚拟机自行定义.然后在Java堆中实例化一个java.lang.Class类的对象,这个对象将作为程序访问方法区中的这些数据的外部接口.
验证
验证阶段的目的,是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全.
Java语言本身是相对安全的语言,如果通过正常的途径编译java类,是基本不会出现不符合虚拟机要求的字节码文件的.但是在之前”加载”这一节说过,java的二进制字节码不一定是通过javac命令编译过来,它可以使用很多途径.甚至你可以通过十六进制编辑器(比如WinHex)直接编写Class文件(当然也可以修改).所以,如果不做验证,危害还是非常大的.
虽然虚拟机规范没有对验证做明确的规定,交给具体的虚拟机来完成.但是每个虚拟机大致上都会完成下面四个阶段:
文件格式验证
这个阶段验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理.这个阶段大概包括:
(1) 魔数是否为CAFEBABE
(2) 主次版本号是否在当前虚拟机处理范围内
(3) 常量池的常量是否有不被支持的常量类型
(4) 指向常量池的索引值是否有指向不存在的常量或者不符合类型的常量
(5) Class文件中各个部分及文件本身是否有被删除的或者附加的其他内容.
(6) ….
上面举了一些验证的规则.但是,注意这个不是验证的全部.这个阶段的验证是基于字节流进行的,经过了这个阶段的验证以后,字节流才会进入内测的方法区进行存储.后面的三个验证阶段全部都是基于方法区的存储结构进行的.
元数据验证
这个阶段的验证是字节码的描述信息进行语义分析,保证其描述的信息符合Java语言规范的要求.这个阶段的验证包括:
(1) 这个类是否有父类.
(2) 这个类的父类是否继承了不允许被继承的类(被final修饰的类).
(3) 如果这个类不是抽象类,是否实现了其父类或者接口的所有抽象方法
(4) 类中的字段,方法是否与父类产生了矛盾.
(5) ….
字节码验证
这个阶段是整个验证过程中最复杂的.主要工作是进行数据流和控制流分析.其实这个阶段就是对类的方法体进行校验分析.例如
(1) 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,比如不会在操作栈中放置一个int类型的数据,使用时却按照Long类型来加载
(2) 保证跳转的指令不会跳转到方法体以外的字节码上
(3) 保证方法体中类型的转换是有效的.
(4) ….
这个验证十分的复杂,而且有一条原则,如果一个类的方法如果字节码没有验证通过,
那说明肯定有问题,但是验证码通过的方法不一定是没有问题的..
正因为这个验证太花时间,所以jdk提供了一些方法来关闭这个验证.比如之前在eclipse优化那里说到的 -Xverify:none 指令就是关闭字节码验证的.
符号引用校验
这个校验阶段发现在虚拟机将符号引用转换为直接引用的时候.这个转换动作是在解析阶段中发生的.通常的校验内容包括:
(1) 符号引用中通过字符串描述的全额定名是否能找到对应的类
(2) 在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段.
(3) 符号引用中的类,方法和字段的隔离级别是否可被当前类访问.
(4) ….
符号引用的校验确保解析动作能正常执行.如果校验不通过,则会抛出java.lang.IncompatibleClassChangeError异常的子类.比如我们常见的java.lang.IllegalAccessError,java.lang.NoSuchFieldError,java.lang.NoSushMethodError.
准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段.这些内容都要在方法区中进行分配.这里需要注意两地啊你
(1)注意这里说的是类变量(也就是说被static修饰的),而不包括实例变量.实例变
量将在对象实例化时随着对象一起分配到Java堆中.
(2)另外一点需要注意的是,这里所说的初始值通常情况下是该类型的零值.这句话本身又需要解释两点,第一,零值是什么.比如
public static int value = 123;
在准备阶段,value值就会被初始化为0..因为Int对应的零值为0,而float类型对应的零值为0f.long类型为0f, 引用类型为null.其实这些都容易理解.
第二,这里说的是,通常情况下是会被赋值为零值,换句话说,还有特殊情况下是会被直接赋值的.这种特殊情况就是:如果该类字段的字段属性表中存放ConstantValue属性,那么准备阶段就会将value的值进行初始化.比如
public static final int value = 123;
这个时候在准备阶段就会 把value值初始化为123;
在最后,我还是解释一下属性表中的ConstantValue属性.由于属性表太过复杂,所以我在写本篇文档的时候并没有将类结构解析中属性表相关部分的文档写完.既然这边说到了属性表中的ConstantValue属性,所以还是解释一下. ConstantValue属性的作用是通过虚拟机自动为静态变量赋值.只有被static修饰的变量才可以使用这项属性.但是这个只是前提,并不是说所有被static修饰的变量都会有对应的ConstantValue属性.在sun的hotspot虚拟机是这么定义的:只有同时使用final 和static修饰的变量(其实就是常量了),并且这个变量的类型是基本数据类型或者String类型,才会在属性表中生成ConstantValue属性.
相关推荐
类的生命周期包括加载、验证、准备、解析和初始化五个阶段。其中,加载是读取.class文件,验证确保字节码安全,准备分配静态变量内存,解析绑定符号引用,初始化执行类的初始化方法。 4. **类的加载条件** 类的...
### 深入研究Java类加载机制 #### 一、Java类加载机制概述 Java类加载机制是Java程序运行的第一步,它对于理解Java虚拟机(JVM)的行为至关重要。...希望本文能够帮助读者更加深入地理解和应用Java类加载机制。
类加载机制不仅涉及到类的加载、验证、准备、解析和初始化等步骤,还包括类加载时机的选择及类加载器的具体工作原理等内容。 #### 一、类加载时机 Java类的生命周期主要包括以下几个阶段:加载、验证、准备、解析...
验证阶段确保字节码的正确性,准备阶段为类的静态变量分配内存并初始化为默认值,解析阶段将符号引用转换为直接引用,初始化阶段执行类的初始化方法 `()`。这些阶段是 JVM 运行时不可或缺的部分,确保了程序的安全性...
- 类加载过程包括加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)和初始化(Initialization)五个阶段。 - Android系统使用双亲委派模型进行类加载,即先由父加载器尝试加载,...
类加载机制包括加载、验证、准备、解析和初始化五个阶段,确保了程序的安全性和稳定性。 1. **加载**:这是类加载的第一步,JVM会通过类加载器找到对应的`.class`文件。类加载器主要有Bootstrap ClassLoader(引导...
验证阶段是链接过程的第一步,目的是确保加载的类文件信息符合JVM规范且不会危害虚拟机的安全。验证包括四个子步骤: - 文件格式验证:检查是否符合.class文件格式,如魔术数字、版本号等。 - 元数据验证:确保类...
解析阶段可能会涉及到类的加载、验证和准备,因此它可能发生在初始化之后。 5. **初始化**:这是类加载的最后阶段,会执行类的初始化代码(即静态初始化块),包括静态变量的显示初始化(如赋值语句)、初始化静态...
1. **类的加载、验证和初始化**:这是类加载机制的核心部分。当程序启动时,JVM会根据应用程序的需求动态地加载所需的类到内存中。这个过程包括三个主要阶段:加载、验证和初始化。其中,加载是将类的二进制数据读入...
本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载机制遵循“双亲委派模型”(Delegation Model)。当一个类被加载时,它首先会尝试由当前...
- 类加载过程包括加载、验证、准备、解析和初始化五个阶段。加载是将类的二进制数据读取到内存中;验证确保类的信息符合JVM规范;准备阶段为类的静态变量分配内存并初始化为默认值;解析将符号引用转换为直接引用;...
类加载机制是 JVM 的核心组件之一,对 Java 程序的执行和安全性起着至关重要的作用。 类加载机制的过程可以分为以下几个阶段: 1. 加载(Loading):在硬盘上查找并通过 IO 读入字节码文件,使用到类时才会加载,...
类的加载机制是Java语言的一个重要特性,它使得Java程序具有了动态链接和装载的能力。通过类加载器的不同设计,可以支持程序的热更新、热部署等功能,极大地提高了程序的灵活性和可维护性。同时,类的加载机制也是...
反射机制和类加载机制是Java编程语言中的两个重要概念。反射提供了强大的运行时元数据操作能力,而类加载机制则确保了类的安全加载和动态管理。深入理解这两个机制对于Java开发者来说至关重要,尤其对于那些从事框架...
总结,Java的类加载机制和双亲委派模型是JVM工作的重要组成部分,理解这些机制有助于优化程序性能,解决类冲突问题,并实现特定的类加载策略。自定义类加载器则提供了扩展JVM类加载功能的可能,使得开发者能够根据...
首先,类加载的过程分为三个主要阶段:加载、验证、准备、解析和初始化。在本文中,我们主要关注加载阶段。加载阶段,Java虚拟机通过类加载器将类的.class文件读取到内存中,并创建对应的java.lang.Class对象。类...
Java 类加载机制是 Java 开发的基础之一,理解和掌握类加载机制有助于开发者解决诸如 `ClassNotFoundException`、`ClassCastException` 等常见问题。此外,通过自定义类加载器,还可以实现更灵活的类加载策略,满足...
类加载器不仅负责加载类,还参与类的生命周期管理,包括链接(验证、准备和解析)、初始化等步骤。`resolveClass()`方法用于链接已加载的类,确保类的静态变量被正确初始化,方法区的数据结构被建立。 5. **类加载...
在链接阶段,类加载器会对加载的类进行链接,包括验证、准备和解析。在初始化阶段,类加载器会对加载的类进行初始化,包括静态变量的初始化和 static 块的执行。 Java 的类加载器机制是 JVM 运行过程中的核心组件,...
Java注解、反射、字节码和类加载机制是Java编程中的核心概念,它们在实际开发中扮演着重要角色。让我们深入探讨这些知识点。 **Java注解(Annotation)**: Java注解是一种元数据,它提供了在编译时或运行时处理代码的...