欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > Java的类加载机制和类对象

Java的类加载机制和类对象

2025/5/10 20:59:25 来源:https://blog.csdn.net/oscar999/article/details/147289136  浏览:    关键词:Java的类加载机制和类对象

在使用Java 语言开发时,Class Loader可能是一个不用关注的概念,但是在某些疑难问题的解决的时候,可能需要掌握相关的知识,比如笔者在这一篇遇到的问题: Spring Boot JPA 开发之Not an entity血案。 接下来就来全面的看一看Java的类加载机制。

一、类加载器(Class Loader)

类加载器是JVM的一部分,负责将类的字节码文件(.class)动态加载到内存中,并生成对应的java.lang.Class对象。Java采用分层类加载模型,主要有以下三类加载器:

  1. Bootstrap ClassLoader(启动类加载器)
    • 职责:加载JVM核心类库(如java.lang.*),路径为<JAVA_HOME>/jre/lib
    • 实现:由C/C++编写,是JVM的一部分,无Java类实例。
    • 特性:唯一没有父加载器的类加载器。
  2. Extension ClassLoader(扩展类加载器)
    • 职责:加载扩展目录(<JAVA_HOME>/jre/lib/ext)中的类。
    • 实现:由sun.misc.Launcher$ExtClassLoader实现,父加载器为Bootstrap。
  3. Application ClassLoader(应用程序类加载器)
    • 职责:加载用户类路径(-classpathCLASSPATH环境变量)的类。
    • 实现:由sun.misc.Launcher$AppClassLoader实现,父加载器为Extension。
  4. 自定义类加载器
    • 场景:需隔离加载(如热部署)、动态加载网络资源等。
    • 实现:继承ClassLoader,重写findClass()方法。

二、类加载机制

类加载过程分为加载、链接(验证、准备、解析)、初始化三个阶段:

  1. 加载(Loading)
    • 操作:查找字节码文件,读取到内存,生成Class对象。
    • 触发条件:首次使用类时(如new、调用静态方法等)。
  2. 链接(Linking)
    • 验证(Verification):检查字节码合法性(格式、语义、安全性)。
    • 准备(Preparation):为静态变量分配内存并赋默认值(如int初始化为0)。
    • 解析(Resolution):将符号引用(类、方法名)转为直接引用(内存地址)。
  3. 初始化(Initialization)
    • 操作:执行静态变量赋值和静态代码块(按代码顺序执行)。
    • 线程安全:JVM保证初始化过程同步。

三、双亲委派模型(Parent Delegation Model)
  1. 机制
    • 类加载器在加载类时,先将请求委派给父加载器。
    • 若父加载器无法完成(在自己的搜索范围内找不到类),子加载器才尝试加载。
  2. 优点
    • 安全性:防止核心类被篡改(如用户自定义java.lang.String无效)。
    • 避免重复:确保类全局唯一性(同一类由同一加载器加载)。
  3. 打破双亲委派
    • 场景:OSGi模块化、Tomcat隔离Web应用。
    • 方法:重写loadClass()逻辑(如优先自行加载)。

四、类对象(Class Object)
  1. 概念
    • 每个类加载后,JVM为其生成一个Class对象,存储类的元数据(方法、字段、构造器等)。
    • 是反射(java.lang.reflect)操作的基础。
  2. 获取方式
    • 类名.class(如String.class)。
    • 对象.getClass()(如new String().getClass())。
    • Class.forName("全限定类名")(动态加载,如Class.forName("java.util.ArrayList"))。
  3. 应用
    • 反射:通过Class对象实例化对象、调用方法、访问字段。
    • 动态代理:基于接口和Class对象生成代理类。

五、关键代码示例
// 自定义类加载器
public class CustomClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {byte[] classData = loadClassData(name); // 从自定义路径读取字节码return defineClass(name, classData, 0, classData.length);}
}// 使用Class对象反射创建实例
Class<?> clazz = Class.forName("com.example.MyClass");
Object obj = clazz.newInstance();
Method method = clazz.getMethod("myMethod");
method.invoke(obj);

六、常见问题
  1. 不同类加载器加载的类是否相同?
    • :即使全限定名相同,不同加载器加载的类在JVM中视为不同类,导致instanceof和类型转换失败。
  2. 何时触发类初始化?
    • new、静态方法调用、静态字段访问(非final)、反射调用Class.forName()(默认初始化)、子类初始化触发父类初始化等。
  3. 如何实现热部署?
    • 自定义类加载器,每次重新加载类生成新Class对象,需注意旧实例与新类不兼容。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词