news 2026/4/16 11:10:53

JVM 标准到底如何定义类加载

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM 标准到底如何定义类加载

内容来自JVMS Chapter 5 – Loading, Linking, and Initialization(类加载、链接、初始化),这是 JVM 规范中对类加载的正式描述。这不是教材版,而是接近 JVM 规范原文的专业总结版

JVM 不定义类加载器的层次结构、不强制双亲委派,也不定义 classpath。 它只要求:类必须通过某个加载器被定义,类的身份由“类名 + 加载器”唯一确定。 加载、链接、初始化的每个环节必须按规范精确执行。

1. JVM 规范中类加载属于更大的过程:

Loading → Linking → Initialization加载 → 链接 → 初始化

JVMS 定义类处理流程分为三大阶段:

1. Loading(加载) 2. Linking(链接) 2.1 Verification(验证) 2.2 Preparation(准备) 2.3 Resolution(解析) 3. Initialization(初始化)

类加载只是整个过程的第一步,不包含解析、初始化。

2. JVM 如何定义 “类加载(Loading)”

JVMS 定义:

Class loading is the process of locating a binary representation of a class or interface and transforming it into the runtime data structure inside the JVM.
类加载 = 找到类的二进制表示,并创建其在 JVM 中的运行时表示。

规范强调三点:

1)“二进制表示”不限于 .class 文件

可以来自:.class/JAR/网络/动态生成的字节数组(如 ASM/CGLIB)/数据库/加密文件
JVM 标准不限制来源。

2)类加载器负责找到这个“二进制表示”

规范中称之为:defineClass findClass

3)加载结果是method area(或 Metaspace)中的 Class 对象

规范描述为:runtime representation of classes 类的运行时表示

3. JVM 规范如何描述类加载器(ClassLoader)

类加载器不是 Java 语言的组成部分

但 JVM 规范要求:

The Java Virtual Machine must maintain a mapping between class loaders and the classes they have loaded.Java
虚拟机必须维护类加载器与其加载的类之间的映射关系。

这意味着:

  • 每个类都有一个加载器标识
  • 类的身份 = (className + classLoader)类的身份= (className + classLoader)

4. JVM 标准如何描述 “类加载器之间的关系”

最关键的一段:

The Java Virtual Machine specification does not require class loaders to follow a parent-child hierarchy.Java
虚拟机规范不要求类加载器遵循父子层次结构

也就是说:

  • 双亲委派不是 JVM 强制的
  • 是 Java ClassLoader 的一种“设计模式”,而不是 JVM 的硬规则
  • JVM 层面只关心“由哪个加载器加载”

5. JVM 规范如何要求加载器委派(parent delegation)

非常重要的一段:

The delegation model is strongly recommended but not strictly required by this specification.
本规范强烈建议采用委托模型,但并非严格要求。

这意味着:

  • HotSpot 的默认加载器链:Bootstrap → Ext/Platform → App
  • Launcher(JDK8)/ClassLoaders(JDK9+)(Java 层)设计的,不是 JVM 强制的
  • 容器(Tomcat/OSGi)可以合法地破坏它(符合规范)

6. JVM 规范如何描述类的唯一性:Class Identity

规范定义类的唯一标识为:

Class Identity = (class name + defining class loader)

因此:

  • 同名类由两个不同 ClassLoader 加载 → 两个不同的类
注意:这里两个不同的ClassLoader可以是不同类型的ClassLoader,也可以是同类型ClassLoader的不同实例
不同类型的ClassLoader:
// 类型1:JDK 自带的 URLClassLoader
URL url = classPath.toUri().toURL();
URLClassLoader urlLoader = new URLClassLoader(new URL[]{url}, null);

// 类型2:我们自己写的 MyFileClassLoader(完全不同类型!)
MyFileClassLoader myLoader = new MyFileClassLoader(classPath, null);

// 加载同一个类
Class<?> c1 = urlLoader.loadClass("a7.Person");
Class<?> c2 = myLoader.loadClass("a7.Person");

不同实例:
// 两个完全一样的 class 文件,但路径不同 → 两个不同的 ClassLoader
URL url1 = Paths.get("D:/MyWork/0-create/practice idea/jvm/jvm-practice/out/production/part4/").toUri().toURL();
URL url2 = Paths.get("D:/MyWork/0-create/practice idea/jvm/jvm-practice/out/production/part4/").toUri().toURL();

// 父加载器都设为 null(直属 Bootstrap),这样更纯粹,也可以设为 getSystemClassLoader()
URLClassLoader loader1 = new URLClassLoader(new URL[]{url1}, null);
URLClassLoader loader2 = new URLClassLoader(new URL[]{url2}, null);

// 加载同一个全限定名的类
Class<?> clazz1 = loader1.loadClass("a7.v1.User");
Class<?> clazz2 = loader2.loadClass("a7.v2.User");
  • 不能相互赋值、不能 instanceof、不能强制转型
这是 OSGi、Tomcat 多版本隔离的理论基础。

7. JVM 如何描述“类加载触发条件”

规范要求,类只有在首次主动使用时才必须加载:

主动使用包括:

  • new 对象
  • 调用静态方法
  • 访问静态字段(非 final)
  • 反射 Class.forName引用 Class.forName
  • 初始化子类(会触发父类加载)
  • JVM 启动加载 main 类

8. JVM 对生命周期的强制要求(重要)

JVM 必须保证:

  1. 类必须按需加载(lazy loading)
  2. 类只能被加载一次(每个 ClassLoader 内)
  3. 同一加载器加载同名类必须返回同一 Class 对象
  4. 加载器之间不能冲突:父和子加载器加载同名类时是两个类

9. JVM 规范对 defineClass 的要求(非常核心)

规范要求 defineClass 只做:

  1. 校验二进制格式
  2. 将其转换为内部运行时结构
  3. 绑定到当前 ClassLoader 的命名空间

不负责:

  • 查找 class
  • 处理委派
  • 管理 classpath管理类路径

这些都是 Java 层的 ClassLoader 负责的。

10. JVM 规范明确双亲委派不是必须 | 自定义加载器合法

自定义 ClassLoader从 JVM 标准的角度完全合法,只要保证:
  • defineClass 的字节码合法
  • 链接验证成功
  • 不替换 java.* 核心类(否则安全管理器会禁止)
  • 不与系统类冲突(除非故意隔离)

下面是一个打破双亲委派的例子(基于jdk17):

import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; public class MyClassLoaderJdk17 extends ClassLoader { private final String classPath; private final String targetPackagePrefix = "com.test"; public MyClassLoaderJdk17(String classPath) { super(MyClassLoaderJdk17.class.getClassLoader()); // parent = app loader this.classPath = classPath; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // JPMS 下绝不能尝试加载 java.*,否则报错 if (name.startsWith("java.") || name.startsWith("jdk.") || name.startsWith("javax.")) { return super.loadClass(name); } // 对业务包破坏双亲委派 if (name.startsWith(targetPackagePrefix)) { synchronized (getClassLoadingLock(name)) { Class<?> loaded = findLoadedClass(name); if (loaded != null) return loaded; try { return findClass(name); } catch (Exception ignored) { } } } // 其余保持默认委派 return super.loadClass(name); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { String file = classPath + "/" + name.replace('.', '/') + ".class"; byte[] bytes = Files.readAllBytes(Paths.get(file)); return defineClass(name, bytes, 0, bytes.length); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } }

因此:

  • Tomcat 的 WebAppClassLoader
  • SPI 的 ThreadContextClassLoader
  • OSGi 的 BundleClassLoader

完全符合 JVM 标准。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 23:22:40

交换机如何搭配光模块使用,这几种方法非常实用

在企业网络部署、数据中心建设都离不开光模块与交换机。光模块主要是用来将电信号与光信号进行转换&#xff0c;而交换机则是对光电信号起到转发作用。在众多光模块中&#xff0c;SFP光模块是目前被应用的最多的光模块之一&#xff0c;在与交换机搭配使用时采用不同的连接方式可…

作者头像 李华
网站建设 2026/4/9 11:06:56

导师推荐10个AI论文平台,专科生轻松搞定毕业论文!

导师推荐10个AI论文平台&#xff0c;专科生轻松搞定毕业论文&#xff01; AI 工具如何助力论文写作&#xff0c;让专科生轻松应对毕业挑战 在当今信息化快速发展的时代&#xff0c;AI 工具正逐步改变着学术写作的方式。对于专科生而言&#xff0c;撰写毕业论文常常面临时间紧…

作者头像 李华
网站建设 2026/4/15 22:17:05

技术架构:海外版外卖平台搭建全攻略

在全球化浪潮和数字化经济的双重推动下&#xff0c;海外外卖市场正迎来爆发式增长。无论是北美、欧洲&#xff0c;还是东南亚、中东&#xff0c;线上订餐已成为现代生活的标配。这为创业者提供了巨大的机遇——打造一个本土化的“UberEats”或“外卖人”平台。本文将深入探讨自…

作者头像 李华
网站建设 2026/4/13 21:02:51

超市收银机(有完整资料)

资料查找方式&#xff1a; 特纳斯电子&#xff08;电子校园网&#xff09;&#xff1a;搜索下面编号即可 编号&#xff1a; CP-51-2021-008-KT 设计简介&#xff1a; 本设计是基于单片机的超市收银机&#xff0c;主要实现以下功能&#xff1a; 扫码枪扫描商品手动输入商品条…

作者头像 李华
网站建设 2026/4/16 11:03:48

宁波银行与南京银行,两个不同的银行物种

作为城商行的两位优等生&#xff0c;日前宁波银行和南京银行都发布了2025年的业绩预告。 截至2025年末&#xff0c;宁波银行总资产36286.01亿元&#xff0c;较年初增长16.11%&#xff1b;实现营业收入719.68亿元&#xff0c;同比增长8.01%&#xff1b;实现归属于母公司股东的净…

作者头像 李华
网站建设 2026/4/11 7:51:46

“十五五”数字智能工厂MES生产执行系统建设方案

“十五五”期间的MES建设&#xff0c;不应再是单一系统的信息化项目&#xff0c;而应是以数据智能为核心&#xff0c;驱动生产运营模式根本性变革的战略工程。本方案勾勒的下一代MES&#xff0c;是一个开放、智能、自适应的制造运营平台&#xff0c;是未来智能工厂的“智慧大脑…

作者头像 李华