java的类加载机制
Java 的类加载机制通过动态加载、内存管理、安全性和代码隔离等功能,为开发者提供了强大的支持,适应了现代应用的需求
一、类的生命周期
类的生命周期包括:加载、链接、初始化、使用和卸载,其中加载、链接、初始化,属于类加载的过程,我们下面仔细讲解。使用是指我们new对象进行使用,卸载指对象被垃圾回收掉了。
如下图:
二、类加载的主要步骤
1. Loading加载
JVM 在该阶段的目的是将字节码从不同的数据源(可能是 class 文件、也可能是 jar 包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的 java.lang.Class 对象。
1)通过类的全限定名(包名 + 类名),获取到该类的.class文件的二进制字节流
2)将这个二进制Å字节流所代表的静态存储结构,转化为方法区运行时的数据结构
3)在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
总结:加载二进制数据到内存 -> 映射成jvm能识别的结构 -> 在内存中生成class文件。
2. 链接(Linking)
1)验证(Verification):检查类的字节码是否符合 JVM 规范,确保安全性。
2)准备(Preparation):为类变量分配内存,并设置默认值。
3)解析(Resolution):将符号引用(如类名、方法名)转换为直接引用(内存地址)。
3. 初始化(Initialization)
执行类的静态初始化方法 <clinit>,这包括初始化静态变量和执行静态代码块。
三、类加载器的类型
类加载器的层次,如下图:
1. 启动类加载器(Bootstrap ClassLoader)
加载 Java 核心类库。
2. 扩展类加载器(Extension ClassLoader)
加载 Java 扩展库。
3. 应用程序类加载器(Application ClassLoader)
加载用户类路径下的类。
4. 自定义加载器
一般情况下,以上3种加载器能满足我们日常的开发工作,不满足时,我们还可以自定义加载器。
比如用网络加载Java类,为了保证传输中的安全性,采用了加密操作,那么以上3种加载器就无法加载这个类,这时候就需要自定义加载器。
四、类的加载方式
1. 命令行启动应用时候由JVM初始化加载
2. 通过Class.forName()方法动态加载
3. 通过ClassLoader.loadClass()方法动态加载
代码示例:
1 package com.pdai.jvm.classloader; 2 public class loaderTest { 3 public static void main(String[] args) throws ClassNotFoundException { 4 ClassLoader loader = HelloWorld.class.getClassLoader(); 5 System.out.println(loader); 6 //使用ClassLoader.loadClass()来加载类,不会执行初始化块 7 loader.loadClass("Test2"); 8 //使用Class.forName()来加载类,默认会执行初始化块 9 // Class.forName("Test2"); 10 //使用Class.forName()来加载类,并指定ClassLoader,初始化时不执行静态块 11 // Class.forName("Test2", false, loader); 12 } 13 } 14 15 public class Test2 { 16 static { 17 System.out.println("静态初始化块执行了!"); 18 } 19 }
五、JVM类加载机制
全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
4. 双亲委派模型 (Parent Delegation Model)
主要用于避免类的重复加载和确保类加载的安全性。其基本思想是:一个类加载器在加载类时,首先将请求委派给它的父类加载器,只有当父类加载器无法找到该类时,子类加载器才会尝试加载。
具体描述为:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类
注意:
使用双亲委派模型有一个很明显的好处,那就是 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系,这对于保证 Java 程序的稳定运作很重要。
上文中曾提到,如果两个类的加载器不同,即使两个类来源于同一个字节码文件,那这两个类就必定不相等——双亲委派模型能够保证同一个类最终会被特定的类加载器加载。
标签:初始化,java,ClassLoader,该类,Java,机制,Class,加载 From: https://www.cnblogs.com/hld123/p/18436634