类加载过程
类一共有七个生命周期:加载->验证->准备->解析->初始化->使用->卸载
加载(加载字节码文件,生成.class对象)
加载是类加载的第一个阶段。 加载阶段的任务是在类文件从磁盘加载到内存中,通常是从classpath中的jar文件或目录中加载。
加载过程不仅仅包括类的字节码,还包括了静态变量(常量池中的常量值)和静态方法(类中的静态方法)的定义。
验证(验证Class文件是否符合规范)
验证是确保类文件的完整性和合法性的过程。
验证器检查类文件是否符合Java虚拟机规范,包括检查字节码的格式、语义等,以防止恶意代码执行。
验证确保了Java程序的安全性。
准备(为静态变量分配内存并设置变量初始值)
准备阶段为类的静态变量分配内存,并为这些变量设置初始值。
这里的初始值通常是零值(zero value),如整数为0,引用为null等。
准备并不包括执行类构造器(类的静态初始化方法),仅分配内存并设置初始值。
解析(初始化常量池中的一些常量)
解析是可选的,它将符号引用解析为直接引用。
在解析过程中,虚拟机将类、方法、字段等符号引用映射到具体的内存地址。
解析通常发生在类的初始化阶段之前。
初始化(初始化对象,并为静态变量赋值)
初始化是类加载过程的最后一步。 在初始化阶段,虚拟机执行类构造器方法,它包括了对类的静态字段进行初始化、静态块的执行等。
初始化是类加载的触发点,当第一次使用一个类(例如,创建对象、调用静态方法、访问静态字段)时,该类将被初始化。
总结一下,类加载过程经历了加载、验证、准备、解析和初始化五个阶段,这些阶段确保了类的正确加载和初始化,同时维护了Java程序的安全性。初学者应该理解这些阶段的作用,以更好地理解Java类加载和运行过程。
类加载器
JVM预定义加载器主要有三种:
启动类加载器(bootstrap class loader)
是加载Java运行时所需的基础类的特殊类加载器。它是JVM内置的类加载器,负责加载JVM运行时必需的核心类库,这些类库包括Java平台类库(Java
API,如java.lang包)以及其他基础组件。
扩展类加载器(Extension ClasLoader)
是Java虚拟机(JVM)的一个内置类加载器,它的主要任务是加载Java标准扩展(Java
Extension)中的类库,这些类库通常位于JRE目录下的lib/ext目录中。扩展类加载器是Java类加载层次中的第二级加载器,其加载范围在类加载层次中位于启动类加载器和应用程序类加载器之间。
应用程序类加载器(系统类加载器)
是Java虚拟机(JVM)的一种内置类加载器,也被称为系统类加载器(System Class Loader)。它是Java类加载层次结构中的最底层加载器,负责加载应用程序中的类.
类加载机制
JVM的类加载机制主要有如下3种
全盘负责
当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
双亲委派
先让父类加载器试图加载改Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类,依次向上找.
双亲委派的优点(安全稳定):
1.当一个类收到类加载请求时,他首先不自己尝试去加载,而是层层向上委派给自己的父类,每一层加载器都如此,因此所有的请求都应该传送到启动类加载器中。
2.具备了带有优先级的层次关系,通过层级关系避免类的重复加载,最主要的为了安全,java核心api中定义的类型不会被随意篡改。
3.打破双亲委派模型:
打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法。
缓存机制
缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为什么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。