类加载——JVM

类加载

加载、连接、初始化、使用、卸载

连接又分为 验证准备解析

类的加载阶又相当于类的生命周期。

找到需要 加载的类 并把 类的信息 加载到 jvm的方法区 ,然后在 堆区实例化 一个 java.lang.Class 对象,作为方法区中这个类的信息的入口。

类加载 其实包括加载、连接、初始化三个阶段。

类加载强调一个jvm能够直接使用所需的类,所以类必须完成初始化。

狭义的类加载

1. Loading 阶段在做什么?

加载(Loading)阶段 :JVM 通过各种途径获取类的二进制字节流 ,并由 ClassLoader 将其"定义"为 JVM 可识别的类,最终在 JVM 内部生成并返回对应的 java.lang.Class 对象。

更具体一点:

  • ClassLoader 根据**类的全限定名(Fully Qualified Name)**定位并获取该类的二进制字节流

    (来源可能是 .classjar、网络、动态生成等)

  • 然后将字节流交给 JVM 去执行"defineClass"这一类的定义过程

  • JVM 完成类的内部结构创建后,返回对应的 java.lang.Class 实例

2. 类的字节流从哪里来?

类的加载方式非常灵活,常见来源包括:

  1. 从本地 .class 文件加载(常用)

    根据类的全路径名找到对应的 .class 文件,读取文件内容得到字节流。

  2. jar/war 等归档包中加载(常用)

    Java 项目打包后,大部分类都位于 jar 包中,类加载器会从包内读取字节流。

  3. 从网络加载(历史上常见)

    例如早期流行的 Applet,可以从远程网络获取字节流并加载。

  4. 运行时动态生成(常见于框架/设计模式)

    按规则即时生成字节码,例如:

    • 动态代理(JDK Proxy / CGLIB)

    • 字节码增强(ASM / ByteBuddy 等)

  5. 从非 .class 的其他格式转换得到(本质相同)

    例如某些自定义格式或加密/压缩的类数据,最终仍会转换为 JVM 可识别的字节流再加载。

    本质:最终目标仍然是"拿到合法的 class 字节码"。


3. 什么时候会触发加载?

不同 JVM 对"加载时机"的实现可能存在差异,具体取决于虚拟机实现。

连接

验证 - 准备 - 解析

  1. 验证(Verification)

    进行类的合法性校验

    对比如 字节码格式变量/方法的合法性数据类型的有效性继承与实现的规范性 等进行检查。

    确保被加载的类能够正常被 JVM 运行。

  2. 准备(Preparation)
    分内存、赋初值

    1. 为类的 静态变量(static) 分配内存,并设为 JVM 默认初始值

    2. 对于 非静态变量(实例变量) ,则不会为它们分配内存。

    注意 :这里的初始值是 JVM 默认赋值,而不是程序里写的赋值。

    规则

    • 基本类型 默认值为 0intlongshortcharbytebooleanfloatdouble

    • 引用类型 默认值为 null

    • 常量的默认值为程序中设定的值,例如:

    java 复制代码
    final static int a = 100;

    则准备阶段 a 的值就是 100

  3. 解析(Resolution)

    把常量池的 符号引用 转换为 直接引用

类的初始化

初始化是类加载过程的最后一个阶段 (Loading → Linking → Initialization)。

在这个阶段,JVM 会执行类的类初始化方法 <clinit>(),也就是把:

  • 静态变量的显式赋值static int a = 1;

  • 静态代码块static { ... }

按源码顺序合并到 <clinit>() 里执行。

注意:在 Linking 的 Preparation 阶段,静态变量只是被分配内存并设置默认值(0/null/false),真正的显式赋值与静态块逻辑是在初始化阶段执行。


什么时候会触发「初始化」?(主动使用 / Active Use)

JVM 对"如何加载"没有完全硬性规范,但对"何时初始化"有明确规则:
只有当类型被"主动使用(direct/active use)"时,才会触发初始化。常见触发点:

  1. new 创建该类实例

  2. 读/写该类的静态字段 (但编译期常量例外,见下)

  3. 调用该类的静态方法

  4. 反射调用上述 1/2/3(如 Class.forName、反射访问静态成员等)

  5. 初始化一个子类时,会先初始化其父类(这是"父类优先"的递归链)

  6. 作为程序入口执行,首次调用包含 main 的那个类时会初始化该类

一个关键例外:编译期常量不会触发初始化

如果是 static final 且是编译期可确定的常量 ,使用它可能被编译器直接内联 ,从而不触发类初始化

class A { static final int X = 1; // 编译期常量 static { System.out.println("A init"); } } System.out.println(A.X); // 很可能不打印 "A init"


初始化时具体"执行什么"?

初始化阶段只做一件事:执行 <clinit>()。因此:

  • 会执行:静态代码块、静态变量的显式赋值

  • 不会执行:实例代码块、实例字段赋值、构造器 (这些属于"对象初始化",由 new 触发并在对象创建时执行)

你原句里"非静态与非静态的静态语法均不执行"建议改成更标准的这句:

类初始化只执行静态初始化逻辑;所有实例初始化逻辑都不会在类初始化阶段执行。


初始化顺序(父类优先)

  • 如果该类有父类:先初始化父类,再初始化子类

  • 同一个类内部:按源码顺序执行静态赋值/静态块(它们共同组成 <clinit>()

你原来的"弗雷德初始化"应当是笔误,标准表述是:

初始化子类会触发父类初始化。

Class文件等概念

Class文件(.class)

  • (读取成)二进制字节流/字节码(byte[])
  • (ClassLoader defineClass) -> Class对象(java.lang.Class 实例)
  • (JVM 用它)-》才能new、反射、调用方法等。

1. Class文件 (.class)

  • 编译器(javac)把.java 编译后的产物,存在磁盘、jar包中。
  • 包含 常量池、字段表、方法表、属性、以及方法的字节码指令等结构。
    "存储介质上的标准化类表示"

2. 二进制字节流(binary bytes/ byte stream)

  • 把class文件都出来后得到的原始二进制数据
  • 常见形态:byte[]InputStream
    还没解析、只是字节序列

3. 字节码(byteCode)

  • class文件里方法体的那段JVM指令序列(比如aload_0, invokevirtual)
  • 区分:
    • 二进制字节流:外层raw bytes(文件、网络读出来的)
    • 字节码:里面方法Code属性中的JVM指令

JVM能执行、解释、编译的指令级表示

4. ClassLoader(类加载器)

  • 负责把 **"类名 -》字节数据"**变成JVM里的类定义的组件。
  • 关键动作
    • loadClass(name):按规则找到并加载(通常还会走双亲委派)
    • findClass(name):具体去哪找字节(classpath/jar/网络/自定义)
    • defineClass(bytes):把字节数组交给 JVM 定义成类
  • 一句话"搬运 + 定义类的工人/管道"

5.Class对象(Class instance)

  • 代码里能拿到的 java.lang.Class<?> 实例,比如 String.class 的那个对象。
  • 表示什么 :某个类在 JVM 中的运行时类型信息入口(反射、获取方法字段、创建实例等)。
  • 同一个类的唯一性 :在一个 ClassLoader 命名空间里,某个类通常对应 唯一的 Class对象;不同 ClassLoader 加载的"同名类"可以是不同的 Class对象(也就是"类隔离")。
  • 一句话"运行时类型信息的句柄/门把手"
相关推荐
符哥20084 小时前
C++ 进阶知识点整理
java·开发语言·jvm
夕除4 小时前
js--15
java·jvm·spring
4311媒体网7 小时前
C语言操作符全解析 C语言操作符详解
java·c语言·jvm
猫头虎16 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
wgslucky17 小时前
jdk17 配置jvm参数中gc的日志及控制日志数量和大小
jvm·gc·-xlog
痴儿哈哈1 天前
自动化机器学习(AutoML)库TPOT使用指南
jvm·数据库·python
野犬寒鸦1 天前
从零起步学习并发编程 || 第七章:ThreadLocal深层解析及常见问题解决方案
java·服务器·开发语言·jvm·后端·学习
闻哥1 天前
Kafka高吞吐量核心揭秘:四大技术架构深度解析
java·jvm·面试·kafka·rabbitmq·springboot
星辰_mya1 天前
Elasticsearch线上问题之慢查询
java·开发语言·jvm
蓝帆傲亦1 天前
代码革命!我用Claude Code 3个月完成1年工作量,这些实战经验全给你
jvm·数据库·oracle