赞
踩
JVM(Java虚拟机)的类加载机制是指在运行Java程序时,将类的字节码加载到内存中,并将其转换为可以被JVM执行的对象的过程。
类加载时机,一般分为以下几种情况:
1. 当创建类的实例对象时,需要先加载该类。
例如: `MyClass obj = new MyClass();`
2. 当访问类的静态成员(静态变量或静态方法)时,需要先加载该类。
例如: `int value = MyClass.staticVariable;`
3. 当使用反射方式访问类时,需要先加载该类。
例如: `Class<?> cls = Class.forName("MyClass");`
4. 当程序中使用到某个类的子类时,需要先加载父类。
例如: `MyChildClass obj = new MyChildClass();`
Java类加载的时间是在程序运行时动态加载类的过程中进行的。
类加载的过程主要分为加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、 初始化(Initialization)几个步骤:
查找并加载类的字节码文件。该阶段将类的字节码加载到内存中,并创建对应的Class对象。根据类的全限定名查找字节码文件,并将其加载到内存中。
主要步骤:
1.通过类的全限定名查找字节码文件:在Loading阶段,JVM会根据类的全限定名(包括包名和类名)来查找对应的字节码文件。通常情况下,字节码文件会存储在类路径下的相应位置。
2.将字节码文件加载到内存中:一旦找到了字节码文件,JVM会将其读取并加载到内存中。这个过程会将字节码数据转换为JVM可以理解和执行的数据结构。
3.创建对应的Class对象:在加载字节码文件的过程中,JVM会为该类创建一个对应的Class对象。这个Class对象包含了该类的各种信息,可以用来获取类的结构、访问类的成员变量和方法等。
注意,Loading阶段只是将类的字节码文件加载到内存中,并创建对应的Class对象,但并不会执行类的初始化代码。类的初始化是在后续的Initialization阶段进行的。
示例:`Class.forName("com.example.MyClass");`
检查字节码文件的结构、语法和语义是否合法。验证字节码文件的正确性和安全性。该阶段确保字节码文件符合Java虚拟机规范,并且不会引发安全问题。
主要步骤:
1.类文件格式验证:验证字节码文件是否符合Java虚拟机规范的格式要求。
示例:检查字节码文件的结构、标记等是否符合规范。
2.元数据验证:验证字节码文件中的元数据信息是否正确。
示例:检查类的继承关系、实现的接口、字段和方法的描述符等是否正确。
3.字节码验证:验证字节码文件的字节码指令是否合法、符合语义规范。
示例:检查字节码指令的类型、操作数的类型和数量等是否符合规范。
4.访问权限验证:验证类、字段和方法的访问权限是否符合规定。
示例:检查类、字段和方法的修饰符,如public、private、protected等是否符合访问权限规则。
5.安全性验证:验证字节码文件是否存在安全漏洞或违规操作。
示例:检查字节码文件中的敏感操作、访问权限等是否符合安全规范。
注意,验证阶段的具体操作和示例可能因具体的Java虚拟机实现而有所不同。Java虚拟机在验证阶段会对字节码文件进行全面的检查,以确保加载的类是合法且安全的。
为类的静态变量分配内存,并设置默认初始值。该阶段为静态变量分配内存空间,并设置默认值。
主要步骤:
1. 为静态变量分配内存空间:在准备阶段,JVM会为类的所有静态变量分配内存空间,以便后续使用。
示例: `public static int count = 0;`
2. 设置默认初始值:在分配内存空间后,JVM会为静态变量设置默认的初始值。
示例:对于整型变量,初始值为0;对于布尔型变量,初始值为false;对于引用类型变量,初始值为null。
注意,准备阶段只是为静态变量分配内存并设置默认初始值,并不涉及静态变量的赋值操作。实际的静态变量赋值是在初始化阶段进行的。
将Java虚拟机常量池内的符号引用转换为直接引用。该阶段将符号引用转换为内存中的直接引用,以便程序可以直接访问目标,提高执行效率。通过解析,Java虚拟机可以将符号引用解析为实际的内存地址,从而避免了每次访问目标时都需要重新解析的开销。
2.4.1、符号引用(Symbolic Reference)
符号引用是在编译阶段或者类加载过程中使用的一种符号表示,它通过符号来描述所引用的目标,包括类、方法、字段等。符号引用并不直接指向内存中的实际位置,而是一个符号化的标识。
2.4.2、直接引用(Direct Reference)
直接引用是在解析阶段将符号引用转换为实际的内存地址,以便程序可以直接访问目标。直接引用是指向内存中实际位置的指针、句柄或偏移量,可以直接用于访问类、方法、字段等。
例如,在解析阶段,将类的符号引用转换为直接引用后,可以直接访问类的静态变量、调用类的方法等,而不需要再通过符号引用进行查找和解析。
总结来说,解析阶段的作用是将符号引用转换为直接引用,使得程序可以直接访问目标,提高执行效率和性能。
2.4.3、主要步骤
1. 类解析:将类的符号引用转换为对应的直接引用。
示例:将类 `com.example.MyClass` 的引用转换为实际的内存地址。
2. 方法解析:将方法的符号引用转换为对应的直接引用。
示例:将方法 `myObject.doSomething()` 的引用转换为实际的内存地址。
3. 字段解析:将字段的符号引用转换为对应的直接引用。
示例:将字段 `myObject.count` 的引用转换为实际的内存地址。
解析阶段的目的是为了在类加载完成后能够快速、直接地访问类的成员。通过将符号引用解析为直接引用,程序可以直接使用类、方法、字段等,而无需再进行符号引用的解析过程。
注意,解析阶段的具体操作和示例可能因具体的Java虚拟机实现而有所不同。Java虚拟机在解析阶段会根据符号引用的信息,将其转换为实际的内存地址,以便程序可以直接访问。
Java类加载的初始化(Initialization)阶段是在类加载过程中的最后一个阶段,执行类的初始化代码,包括静态变量赋值和静态代码块的执行。该阶段执行类的初始化代码,初始化静态变量,并执行静态代码块中的逻辑。
主要步骤:
1. 静态变量赋值:在初始化阶段,会为静态变量赋予指定的值,可以是默认值或者程序员指定的初始值。
示例: `public static int count = 0;`
2. 静态代码块的执行:在初始化阶段,会执行类中的静态代码块,这些代码块可以包含任意的Java语句,用于完成一些静态数据的初始化或其他静态操作。
- 示例:
- static {
- // 静态代码块中的逻辑
- System.out.println("Static block executed.");
- }
3. 调用其他类的初始化方法:在初始化阶段,如果类的父类还未被初始化,则会先触发父类的初始化操作,确保父类的初始化在子类之前完成。
注意,初始化阶段是在类加载过程中的最后一个阶段,只有在真正使用类时才会进行初始化。而且,初始化操作只会执行一次,即使多次加载同一个类,也只会执行一次初始化代码。
示例中,当程序执行到 `Main` 类的 `main` 方法时,会触发对 `MyClass` 类的初始化。在初始化阶段,静态代码块会被执行,将静态变量 `count` 赋值为10。然后,通过调用 `MyClass` 类的静态方法 `doSomething()` ,会执行静态方法中的逻辑。
- 示例:
- public class MyClass {
- public static int count = 0;
-
- static {
- // 静态代码块中的逻辑
- System.out.println("Static block executed.");
- count = 10;
- }
-
- public static void doSomething() {
- // 静态方法中的逻辑
- System.out.println("Doing something.");
- }
- }
-
- public class Main {
- public static void main(String[] args) {
- // 使用类的静态成员
- System.out.println(MyClass.count); // 输出:10
- MyClass.doSomething(); // 输出:Doing something.
- }
- }
2.6、 使用(Usage)
使用(Usage)阶段是在类加载完成后,通过创建实例对象或直接访问类的静态成员来使用类。通过实例对象可以调用实例方法和访问实例变量,而通过类名可以调用静态方法和访问静态变量。
可能执行的一些操作:
1. 创建类的实例对象:在使用阶段,可以通过关键字 `new` 来创建类的实例对象,以便使用类的实例方法和实例变量。
示例: `MyClass obj = new MyClass();`
2. 调用类的实例方法:通过类的实例对象,可以调用类的实例方法来执行相应的逻辑操作。
示例: `obj.doSomething();`
3. 访问类的实例变量:通过类的实例对象,可以访问类的实例变量来获取或修改其值。
示例: `int value = obj.getCount();`
4. 调用类的静态方法:可以直接通过类名调用类的静态方法,无需创建类的实例对象。
示例: `MyClass.doStaticSomething();`
5. 访问类的静态变量:可以直接通过类名访问类的静态变量,无需创建类的实例对象。
示例: `int value = MyClass.staticVariable;`
示例中,通过创建 `MyClass` 类的实例对象 `obj` ,可以调用实例方法 `doSomething()` 和访问实例变量 `count` 。同时,通过类名 `MyClass` 可以调用静态方法 `doStaticSomething()` 和访问静态变量 `staticVariable` 。
- 示例:
- public class MyClass {
- public int count;
- public static int staticVariable;
-
- public void doSomething() {
- // 实例方法中的逻辑
- System.out.println("Doing something.");
- }
-
- public static void doStaticSomething() {
- // 静态方法中的逻辑
- System.out.println("Doing static something.");
- }
- }
-
- public class Main {
- public static void main(String[] args) {
- // 创建类的实例对象
- MyClass obj = new MyClass();
-
- // 调用实例方法
- obj.doSomething();
-
- // 访问实例变量
- obj.count = 10;
- System.out.println(obj.count);
-
- // 调用静态方法
- MyClass.doStaticSomething();
-
- // 访问静态变量
- MyClass.staticVariable = 20;
- System.out.println(MyClass.staticVariable);
- }
- }
2.7、 卸载(Unloading)
Java类卸载(Unloading)阶段是在类不再被引用或程序结束时进行的,它会释放类所占用的内存空间。
可能执行的一些操作:
1. 卸载类的实例对象:当类的实例对象不再被引用或被垃圾回收器回收时,卸载阶段会释放实例对象所占用的内存空间。
示例:当实例对象 `obj` 不再被引用时,可能会触发卸载阶段。
2. 卸载类的静态成员:当类的静态成员不再被引用或程序结束时,卸载阶段会释放静态成员所占用的内存空间。
示例:当静态变量 `count` 不再被引用时,可能会触发卸载阶段。
注意,卸载阶段的具体触发时机是由Java虚拟机的垃圾回收器来决定的。当类不再被引用或无法被访问时,垃圾回收器可能会判断该类可以被卸载,并在适当的时候进行卸载操作。
示例中,当程序运行结束后,可能会触发对 `MyClass` 类的卸载。在卸载阶段,会释放类所占用的内存空间。
- 示例:
- public class MyClass {
- // 类的定义
- }
-
- public class Main {
- public static void main(String[] args) {
- // 使用类的实例对象或静态成员
- MyClass obj = new MyClass();
- obj.doSomething();
- int value = MyClass.staticVariable;
-
- // 程序结束后,可能触发类的卸载
- }
- }
注意,Java虚拟机的具体实现可能会有所不同,卸载阶段的触发时机和具体操作可能因虚拟机的不同而有所差异。
类加载器(ClassLoader)是负责加载类的重要组件,它负责将类的字节码文件加载到内存中。
JVM内置了三种类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)、用户自定义加载器。
启动类加载器(Bootstrap ClassLoader)是Java虚拟机内置的类加载器,负责加载Java运行时环境的核心类库,如 `java.lang` 等。它是虚拟机的一部分,由C++实现,并不是一个Java类。启动类加载器无法被Java程序直接引用。
扩展类加载器(Extension ClassLoader)是Java虚拟机的内置类加载器之一,负责加载Java扩展类库,如 `javax` 等。它是由Java编写的类加载器,是 `sun.misc.Launcher$ExtClassLoader` 的实例。
应用程序类加载器(Application ClassLoader)是Java虚拟机的内置类加载器之一,也被称为系统类加载器,负责加载应用程序的类。它是由Java编写的类加载器,是 `sun.misc.Launcher$AppClassLoader` 的实例。
用户可以根据需要自定义自己的类加载器(User ClassLoader),继承 `java.lang.ClassLoader` 类,并实现加载类的逻辑。用户自定义加载器可以用于加载特定的类或资源,实现类加载的定制化。 示例中,自定义加载器 `CustomClassLoader` 继承自 `ClassLoader` 类,并重写了 `findClass` 方法来实现类加载的逻辑。然后通过实例化自定义加载器,并调用 `loadClass` 方法来加载指定的类。
- 示例:
- public class CustomClassLoader extends ClassLoader {
- @Override
- public Class<?> findClass(String name) throws ClassNotFoundException {
- // 自定义加载类的逻辑
- byte[] byteCode = loadClassData(name);
- return defineClass(name, byteCode, 0, byteCode.length);
- }
-
- private byte[] loadClassData(String name) {
- // 加载类字节码的逻辑
- // ...
- }
- }
-
- // 使用自定义加载器加载类
- CustomClassLoader customClassLoader = new CustomClassLoader();
- Class<?> myClass = customClassLoader.loadClass("com.example.MyClass");
-
双亲委派(Parents Delegation Model)是类加载器的一种工作机制。当一个类加载器收到加载类的请求时,它首先将该请求委派给父类加载器,只有在父类加载器无法加载该类时,才由当前类加载器自己加载。这种机制可以确保类的加载是从上至下的层级关系,避免重复加载和冲突。
Delegation [ˌdelɪˈɡeɪʃn] n. 代表团; 委托; 委派;
双亲委派的工作过程简述:
1. 当一个类加载器收到加载类的请求时,它首先会检查是否已经加载过该类。如果已经加载过,则直接返回该类的Class对象。
2. 如果该类还未被加载过,当前类加载器会将加载请求委派给其父类加载器。
3. 父类加载器接收到加载请求后,会按照相同的方式进行检查和委派。如果父类加载器能够加载该类,则返回该类的Class对象。
4. 如果父类加载器无法加载该类,则将加载请求再次委派给它的父类加载器,依次往上层的父类加载器进行委派。
5. 如果所有的父类加载器都无法加载该类,则当前类加载器会尝试自己加载该类。它会通过自己的加载机制,查找类的字节码文件,并将其加载到内存中。
6. 加载完成后,当前类加载器会创建该类的Class对象,并返回给上层的类加载器。
通过这种委派方式,类加载器会按照层级关系从上至下依次尝试加载类。这样可以确保类的加载是有序的,避免了重复加载和冲突的问题。
示例:
假设有以下类加载器层级关系:
Bootstrap ClassLoader(启动类加载器) -> Extension ClassLoader(扩展类加载器) -> Application ClassLoader(应用程序类加载器)。
当应用程序需要加载类 `com.example.MyClass` 时,双亲委派模型的工作过程如下:
1. Application ClassLoader收到加载请求,首先检查是否已加载过 `com.example.MyClass` 。
2. 如果没有加载过,则将加载请求委派给Extension ClassLoader。
3. Extension ClassLoader接收到请求后,也会检查是否已加载过该类。如果没有加载过,则将请求委派给Bootstrap ClassLoader。
4. Bootstrap ClassLoader检查后发现没有加载过该类,因此尝试自己加载 `com.example.MyClass` 。
5. 如果Bootstrap ClassLoader也无法加载该类,则会返回给Extension ClassLoader。
6. Extension ClassLoader收到返回后,再次尝试加载该类。如果仍然无法加载,则将请求返回给Application ClassLoader。
7. 最后,Application ClassLoader尝试自己加载该类。如果成功加载,则返回 `com.example.MyClass` 的Class对象。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。