当前位置: 首页 > news >正文

类与类加载器

在Java中,类和类加载器是密切相关的两个概念,理解它们有助于我们更好地掌握Java的运行机制。

什么是Java类?

Java类就像是一个模板或蓝图,它定义了对象的属性和行为。比如"汽车"可以看作一个类,它有颜色、品牌等属性,有行驶、刹车等行为。我们根据这个类可以创建具体的汽车对象(如一辆红色的特斯拉)。

// 汽车类(模板)
class Car {String color;  // 属性String brand;  // 属性// 行为void drive() {System.out.println(brand + "汽车正在行驶");}
}// 创建对象(根据模板造具体的车)
Car myCar = new Car();
myCar.color = "红色";
myCar.brand = "特斯拉";
myCar.drive();  // 输出:特斯拉汽车正在行驶

什么是类加载器?

类加载器(ClassLoader)就像是"类的搬运工",它的作用是把.class文件(编译后的类)加载到Java虚拟机(JVM)中,让JVM能够认识这个类并使用它。

想象一下:JVM就像一个大型工厂,类就像是生产所需的图纸。类加载器的工作就是把这些图纸从文件系统、网络或其他地方运送到工厂里,供工厂使用。

咱们可以把Java虚拟机(JVM)想象成一个“大工厂”,类加载器就是负责给这个工厂“运图纸(类)”的工人。

从虚拟机角度看(两种类加载器)

  • 启动类加载器(Bootstrap ClassLoader):它是工厂里“最核心的元老级搬运工”,用C++写的,是虚拟机本身的一部分。专门搬最基础、最核心的“工厂自带图纸”,像java.lang.String这类Java最根本的类,就靠它搬。
  • 其他类加载器:这些是“后来的搬运工”,用Java写的,和虚拟机是分开的。它们都得继承java.lang.ClassLoader这个抽象类,负责搬一些额外的图纸。

从开发者角度看(更细致的划分)

  • 启动类加载器:还是那个“核心元老搬运工”,负责搬<JRE_HOME>\lib目录里(或者-Xbootclasspath参数指定路径里)、虚拟机能认出来的“核心图纸”。比如java.util(工具类)、java.io(输入输出类)、java.lang(语言基础类)这些常用基础类库。而且它很“傲娇”,只认文件名,像rt.jar这类符合名字的才搬,名字不对的,哪怕在lib目录里也不管。另外,Java程序没法直接调用它。

  • 扩展类加载器(Extension ClassLoader):它是“扩展搬运工”,负责搬<JRE_HOME>/lib/ext目录或者java.ext.dir系统变量指定路径里的“扩展图纸”。像swing(界面相关)、内置js引擎、xml解析器这些以javax开头的扩展类库,都由它来搬。开发者是可以直接用这个加载器的。

  • 应用程序类加载器(Application ClassLoader):也叫“系统类加载器”,是“用户搬运工”。负责搬用户自己指定的类路径(ClassPath)里的“图纸”,比如我们自己写的类,或者第三方的jar包。如果我们没自己定义类加载器,程序默认就用它来搬图纸。而且它可以通过ClassLoadergetSystemClassLoader()方法获取到,开发者能直接使用。

类与类加载器的关系

  • 每个类被加载到JVM后,都会记录是被哪个类加载器加载的
  • 类加载器之间存在"父子关系":Application的父是Extension,Extension的父是Bootstrap
  • 判断两个类是否相同,不仅要看类名是否一样,还要看它们是否被同一个类加载器加载

打个比方:两个名字相同的"汽车"图纸,如果一个是由"中国搬运工"搬来的,一个是由"美国搬运工"搬来的,JVM会认为它们是不同的类。

为什么需要类加载器?

  1. 实现了类的动态加载:需要用某个类时才加载,不用时不加载,节省资源
  2. 实现了隔离性:不同的类加载器可以加载同名类而不冲突,这对容器(如Tomcat)很重要
  3. 安全性:可以通过自定义类加载器来控制哪些类能被加载,防止恶意代码

理解类和类加载器的关系,有助于我们解决类冲突、类找不到等问题,也是学习Java反射、动态代理等高级特性的基础。

在Java类加载机制中,双亲委派模型可以类比成一个公司的文件审批流程,这样能更通俗易懂地理解。

什么是双亲委派模型

在Java里,类加载器之间存在层次关系,形成了一个类似树形的结构。除了最顶层的启动类加载器 ,其他类加载器都有自己的“父加载器”,比如扩展类加载器的父加载器是启动类加载器,应用程序类加载器的父加载器是扩展类加载器。双亲委派模型规定,当一个类加载器收到类加载请求时,它首先不会自己去尝试加载这个类,而是把请求委派给父加载器去完成,只有当父加载器无法完成加载任务时,子加载器才会尝试自己去加载。

用公司审批流程举例说明

假设你在公司里写了一份重要的报告,需要经过审批才能正式发布。这就类似于类加载器收到加载类的请求。

  • 部门经理(应用程序类加载器):你作为普通员工,写好报告后会先交给部门经理,对应应用程序类加载器收到类加载请求,它不会自己先去处理,而是把请求向上提交。
  • 部门总监(扩展类加载器):部门经理拿到你的报告后,不会直接审批,而是交给部门总监,这就好比应用程序类加载器把加载请求交给扩展类加载器。部门总监拿到报告后,同样也不会直接审批,而是继续往上提交。
  • 公司老板(启动类加载器):部门总监把报告交给公司老板,启动类加载器作为最顶层,先检查这个报告(类)是不是属于它负责的核心内容,比如公司的基本规章制度、财务审批流程等相关文件(Java核心类库) 。如果是,老板就直接审批(加载类);如果不是,比如是关于某个项目的具体报告,老板就会把报告打回给部门总监,说“这事儿不归我管,你处理一下”。
  • 部门总监处理:部门总监接到老板打回的报告后,查看是否属于自己职责范围内,比如一些技术规范、行业标准相关的报告,如果是就审批(加载类);如果不是,再打回给部门经理。
  • 部门经理处理:部门经理接到报告,一看是关于自己部门项目执行情况的报告,就自己审批了(应用程序类加载器自己加载类)。

双亲委派模型的好处

  • 避免重复加载:如果父加载器已经加载过这个类,子加载器就不需要再加载了,节省了资源。就像在公司审批流程中,如果高层已经审批过类似的文件,底层就不用重复审批。
  • 保证安全性:它确保了Java核心类库的一致性和安全性。因为核心类库都是由最顶层的启动类加载器加载的,防止了用户自定义的类去替换核心类。比如不会出现有人写一个假的java.lang.String类混入系统,因为启动类加载器只会加载真正的核心String类 。

对象的创建过程

咱们把Java中对象的创建过程,比作"盖房子"的过程,这样就很好理解了:

  1. 确定图纸(类加载检查)


1.当你说new 房子()时,JVM首先会检查"房子"这个类的图纸(.class文件)有没有被加载到内存里。如果没加载,就会让类加载器去把图纸搬过来(类加载过程)。
就像盖房子前,必须先有建筑图纸,而且图纸得先拿到工地才行。

  1. 圈地(分配内存)
    图纸确认后,JVM会在内存里找一块合适的地方(堆内存),专门用来盖这个房子(存放对象)。
    相当于开发商在空地上圈出一块地,大小刚好够盖这栋房子。

  1. 地基处理(初始化零值)
    圈好地后,JVM会先把这块地"打扫干净",给里面的各种属性(比如房子的面积、房间数)设置默认值(数字0、布尔false、引用null等)。
    就像盖房子前,先把地皮整平,打好地基,确保基础是合格的。

  1. 挂门牌(设置对象头)
    JVM会给这个对象加一个"身份证"(对象头),里面记录着:这个对象属于哪个类(对应哪个图纸)、哈希码、GC信息等。
    相当于给房子挂上门牌,写明"这是XX小区3号楼",方便后续查找和管理。

  1. 内部装修(执行初始化)
    最后一步是真正按照图纸装修:给属性赋值(比如面积120平米、3个房间)、执行构造方法里的逻辑(比如安装门窗、铺地板)。
    到这一步,房子才算真正盖好,能住人(使用对象)了。

总结一下:从确认图纸→分配空间→基础处理→标记身份→详细装修,一步不差,一个对象就创建出来了。就像盖房子一样,按流程来才能保证最终的"房子"能用、好用。

http://www.dtcms.com/a/334544.html

相关文章:

  • 基于GIS的无人机模拟飞行控制系统设计与实现
  • 某智慧教育平台登录流程分析
  • 元宇宙娱乐:重构数字时代的沉浸式体验
  • 嵌入式 Linux LED 驱动开发实验
  • RK3568 NPU RKNN(五):RKNN-ToolKit-lite2板端推理
  • 要导入StandardScaler类进行数据标准化,请使用以下语句:
  • JavaScript学习第十章-第三部分(dom)
  • B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • C#计算阶乘程序改进
  • C# 元组的用法
  • Nona生命之树作品TRO突袭,冻结名单曝光
  • Vue2.x核心技术与实战(一)
  • 摩搭api 实现
  • 025 理解文件系统
  • 多机编队——(6)解决机器人跟踪过程中mpc控制转圈问题
  • 第四章 Linux实用操作
  • OpenJDK 17的C1和C2编译器实现中,方法返回前插入安全点(Safepoint Poll)的机制
  • 【LeetCode题解】LeetCode 35. 搜索插入位置
  • [Linux] Linux逻辑卷管理
  • 知识点汇总linuxC高级 -2系统命令压缩与链接
  • RK3568 NPU RKNN(三):RKNN-ToolKit2模型构建与推理
  • 【LeetCode】算法详解#13 ---回文链表
  • Vue 3.5重磅更新:响应式Props解构,让组件开发更简洁高效
  • [Linux] Linux交换空间管理 Linux系统启动原理
  • 慧穗云开放平台 CDK 开票对接
  • echart中x的0位置出现柱子宽度被裁掉一部分的问题
  • 技术日记2025年08月16日
  • 基于FPGA的实时图像处理系统(1)——SDRAM回环测试
  • python---异常处理
  • Redis知识整理