不知道和你了解的类加载有没有区别

本文介绍了Java虚拟机的基础概念,包括其生命周期、运行时的数据区组成(如方法区、堆内存、栈内存及PC寄存器)、类加载子系统的功能与工作流程,以及类加载机制的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Java虚拟机的生命周期:

       每个java程序启动都会由虚拟机创建一个java虚拟机实例,那么这个java程序就会在本身的java虚拟机实例上运行,当该java程序关闭退出,本身的java虚拟机实例也会随之消亡.

 

2.Java虚拟机运行时的数据区:

       每个java虚拟机实例都有方法区,堆内存,栈内存,,PC寄存器

1):方法区:它是每个虚拟机实例中所有的线程所共享的,,当虚拟机加载一个class文件时,它会从这个class文件中所包含的二进制数据中解析信息,然后把这些信息放到方法区中;

 

2):堆内存:当java程序运行时,虚拟机会把所有该程序运行时创建的对象放到堆内中;

 

3)栈内存:总是存储java程序中线程调用方法的状态,包括它的局部变量,被调用时传进来的参数,返回值,以及运算的中间结果等,栈是由许多栈帧组成的,一个栈帧包含一个Java方法调用的状态,当线程调用一个Java方法时,虚拟机压入一个新的栈帧到该线程的Java栈中,当该方法返回时,这个栈帧就被从Java栈中弹出并抛弃;

 

4):PC寄存器(也叫程序计数器):如果线程正在执行的是一个Java方法,那么PC寄存器的值总是指向下一条将被执行的指令.

 

3.Java虚拟机的类加载子系统:

              1):在Java虚拟机中,负责查找并加载类型的那部分成为类加载子系统,有两种类加载器,分别为启动类加载器和用户自定义类加载器,前者是Java虚拟机实现的一部分,后者是Java程序的一部分,由不同的类加载器加载的类将被放在虚拟机内部的不同命名空间中;

 

              2):用户自定义的类加载器就是普通的Java对象,它的类必须派生自java.lang.ClassLoader类,ClassLoader中定义的方法为程序提供了访问类加载器机制的接口;

 

              3)类加载器子系统除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用.这些动作必须严格按照以下顺序进行:

                     a)加载 ----- 查找并加载类型的二进制数据

                     b)连接 ----- 指向验证,准备以及解析

                            验证: 确保被导入类型的正确性

                            准备:  为类变量分配内存,并将其初始化为默认值

                            解析:  把类型中的符号引用转化为直接引用

                     c)初始化 ----- 把类变量初始化为正确的初始值

              4)类加载器的特性:

                     a)每个Java虚拟机实现都必须有一个启动类加载器,它们知道怎么加载受信任的类,有自己的命名空间,其中维护着由它装载的类型,所以一个Java程序可以多次加载具有同样的全限定名的多个类型,.

 

                     b)虚拟机必须为每个被加载的类型维护一个常量池,常量池就是该类型所用常量的一个有序集合,包括直接常量和对其他类型,字段和方法的符号引用.池中的数据就像数组一样是通过索引访问的.因为常量池存储了相应类型所用到的所用类型,字段和方法的符号引用,所以它在Java程序的动态连接中起着核心的作用.

4.类加载机制:

        1)通过一个类的全限定名来获取其定义的二进制字节流

       2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构   

       3)在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区中中这些数据的访问入口:

       注意:二进制字节流并不只是单纯地从class文件中获取,它还可以从jar包中获取,从网络中获取.整个类加载过程中,除了在加载阶段用户应用程序可以自定义类加载器参与之外,其余所有的动作完全由虚拟机主导和控制.到了初始化才开始执行类中定义的Java程序代码,类加载过程中主要是将Class文件,也就是类的二进制文件加载到虚拟机内存中,真正执行字节码的操作,在加载完成后才真正开始.

<think>嗯,用户问的是关于类加载器有哪些的问题。首先,我需要回忆一下JVM类加载器的相关知识。类加载器是Java虚拟机JVM)用来动态加载Java的重要组件。根据我的理解,类加载器主要分为几个层次,包括启动类加载器、扩展类加载器、系统类加载器,可能还有自定义类加载器。过,我得确认这些名称是否正确,以及每个加载器的具体职责是什么。 用户之前的问题是关于程序计数器为什么属于JVM内存模型,现在转向类加载器,可能是因为在学习JVM结构的同部分。用户可能对类加载机制太清楚,或者想了解类加载器的区别应用场景。需要确保回答结构清晰,分点说明,并且用例子帮助理解。 首先,启动类加载器(Bootstrap ClassLoader),这个加载器是用C++实现的,负责加载Java的核心库,比如rt.jar。它是最顶层的类加载器,没有父加载器。然后是扩展类加载器(Extension ClassLoader),负责加载JRE的扩展目录中的,比如lib/ext目录下的jar包。接下来是应用程序类加载器(Application ClassLoader),也称为系统类加载器,负责加载用户路径(ClassPath)上的库。这三个是JVM自带的类加载器,遵循双亲委派模型。 另外,还有自定义类加载器,用户可以根据需要继承ClassLoader,实现自己的类加载逻辑。比如,Tomcat使用自定义类加载器来隔离同的Web应用,或者实现热部署功能。自定义类加载器打破了双亲委派模型,需要特别注意冲突的问题。 需要检查是否还有其他型的类加载器,比如线程上下文类加载器,过这可能属于系统类加载器的变体。或者像Java 9引入的模块化系统对类加载器的影响,但可能用户的问题更关注传统结构,所以暂时提模块化系统。 可能用户会混淆类加载器的层次结构,所以在回答时需要明确它们的层次关系加载范围。双亲委派模型的工作机制也很重要,每个类加载器在加载时先委派给父加载器,只有当父加载器无法完成时才自己加载。这种机制保证了Java核心库的型安全,防止用户自定义覆盖核心。 同时,要举例子说明各个类加载器的具体应用场景,比如启动类加载加载java.lang.Object,扩展类加载加载javax包中的,系统类加载加载用户自己编写的。自定义类加载器的例子如OSGi框架、Tomcat等。 需要注意术语的准确性,比如Bootstrap ClassLoader是否真的由C++实现,而其他类加载器由Java实现。此外,类加载器的父子关系是否是继承关系,还是组合关系。在双亲委派模型中,父加载器并是通过继承实现,而是通过组合的方式,每个类加载器持有父加载器的引用。 用户可能还想知道类加载器在实际开发中的应用,比如如何实现热部署,或者解决冲突。这时候可以简要说明自定义类加载器的作用,比如每个Web应用使用独立的类加载器,避免同应用之间的冲突。 总结一下,回答的结构应该是:首先介绍类加载器的作用,然后分点说明各个内置类加载器(启动、扩展、系统),再讲自定义类加载器,最后可以提一下双亲委派模型实际应用例子。确保用中文,避免使用Markdown格式,语言口语化,符合思考过程。</think>类加载器是Java虚拟机JVM)用来动态加载的核心组件,它们像“搬运工”一样把.class文件搬运到内存中。常见的类加载器主要分为四,各司其职: --- ### 一、**启动类加载器(Bootstrap ClassLoader)** - **地位**:类加载器家族的老祖宗 - **职责**:加载`JAVA_HOME/lib`目录下的核心库(如rt.jar、charsets.jar) - **特点**: - 由C++实现(你看到它的Java代码) - 没有父类加载器(它是顶层的存在) - 加载`java.lang.Object`、`java.lang.String`等核心 *示例*: 当你写`new String()`时,实际由它加载`java.lang.String` --- ### 二、**扩展类加载器(Extension ClassLoader)** - **地位**:二当家 - **职责**:加载`JAVA_HOME/lib/ext`目录下的扩展包 - **特点**: - 由Java实现(对应`sun.misc.Launcher$ExtClassLoader`) - 父加载器是启动类加载器 - 加载像`javax.servlet`这种扩展API *示例*: 使用XML解析器时,可能由它加载相关扩展 --- ### 三、**应用程序类加载器(Application ClassLoader)** - **别名**:系统类加载器(System ClassLoader) - **职责**:加载用户路径(ClassPath)下的 - **特点**: - 由Java实现(对应`sun.misc.Launcher$AppClassLoader`) - 父加载器是扩展类加载器 - 你写的`Main.java`编译后的,默认由它加载 *示例*: 执行`java -jar myapp.jar`时,它负责加载你写的所有业务 --- ### 四、**自定义类加载器** - **作用**:打破双亲委派机制,实现特殊需求 - **常见场景**: 1. 热部署(如Tomcat修改代码用重启) 2. 隔离(防止同模块的冲突) 3. 加密解密(加载加密的.class文件) - **实现方式**:继承`ClassLoader`,重写`findClass()`方法 *实际应用案例*: - Tomcat为每个Web应用创建独立的类加载器 - OSGi框架通过自定义加载器实现模块化 --- ### 五、**双亲委派模型(关键机制)** 所有类加载器都遵循这个“先请示上级”的工作流程: 1. 收到类加载请求时,先自己处理 2. 逐级向上委托给父加载器 3. 父加载器无法完成时,才自己加载 *举个栗子*: 当你尝试加载`java.lang.Object`时,最终会由启动类加载器完成加载,避免用户自定义的Object覆盖核心库。 --- ### 六、**为什么需要这么多类加载器?** 1. **安全防护**:防止核心被篡改(比如你无法自定义`java.lang.String`) 2. **职责分离**:同层级加载同重要程度的 3. **灵活扩展**:通过自定义加载器突破限制(比如实现热更新) --- ### 总结 - **内置三大加载器**:启动(搬砖核心库)→ 扩展(搬砖扩展包)→ 应用(搬砖你的代码) - **自定义加载器**:解决特殊场景需求(相当于定制化搬运工) - **工作原则**:双亲委派机制像“家族企业”,小事让底层处理,大事必须请示上级 理解类加载器层级,就像搞懂快递公司的配送体系——总仓发核心货物(启动类加载器),区域仓发扩展件(扩展类加载器),最后快递员(应用类加载器)把包裹送到你家门口!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值