编译期不加载类,运行期才真正加载类:编译期由javac完成语法检查与字节码生成,不启动jvm、不执行static块;运行期由jvm通过类加载器完成加载、连接(验证、准备、解析)、初始化(执行static块)全过程。

编译期不加载类,运行期才真正加载类——这是最根本的区分点。编译期只做语法检查和字节码生成,连JVM都不启动;而类加载是JVM在运行时把.class文件读进内存、校验结构、准备静态变量、执行静态块的全过程。
编译期:javac干活,不碰JVM
这个阶段由javac编译器独立完成,输入.java源文件,输出.class字节码。它不做任何类加载动作:
- 不会去磁盘找Student.class或加载它到内存
- 不会执行任何static代码块,也不会给static变量赋真实值(只检查语法是否合法)
- 遇到
new Student(),只确认Student类名存在、构造方法签名可匹配,不验证Student.class是否存在 - 若引用了不存在的类(如拼错类名),报
cannot find symbol,属于编译错误,不是类加载失败
运行期:JVM启动后才开始类加载
当执行java MainApp时,JVM进程启动,此时才触发类加载机制。以new Student()为例:
- JVM发现当前方法区没有Student类信息,立即发起加载(Loading):从classpath或自定义路径读取Student.class二进制流
- 接着进入连接(Linking):验证字节码合法性 → 为
public static int age = 18在方法区分配内存并设默认值0(准备阶段)→ 把符号引用转为直接引用(解析阶段) - 最后执行初始化(Initialization):运行static代码块,把age真正赋值为18
- 这个过程一旦失败(如文件缺失、版本不兼容、校验失败),抛出
NoClassDefFoundError或ClassNotFoundException,属于运行时异常
一个关键信号:静态代码块是否执行
静态代码块(static { ... })是判断是否进入初始化阶段的明确标志:
- 编译期:完全无视static块,既不执行也不检查其中逻辑
- 运行期:只有该类被首次主动使用(如new实例、调用静态方法、访问静态字段等),JVM才会走到初始化阶段,此时static块才执行一次
- 所以看到控制台打印“✅ Student类 初始化完成”,就说明已过编译期,正在运行期走类加载流程
动态编译是个例外,但本质仍分两步
像通过Java Compiler API在运行时编译.java为.class,看起来“运行中编译”,但它仍是两个分离动作:
- 先调用javac逻辑(模拟编译期行为),生成字节码byte[]或临时.class文件
- 再用自定义ClassLoader显式调用
defineClass(),才算真正进入运行期的类加载 - 即便跳过磁盘写入,字节码也必须经ClassLoader加载进JVM内存,才能被new或反射使用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











