深入理解 Java RTTI、Class 对象、ClassLoader 与反射机制原理
在 Java 进阶学习过程中,RTTI、Class 对象、类加载器、双亲委派模型、反射机制是一条完整的知识链。理解它们之间的关系,就等于掌握了 Java 运行时世界的底层逻辑。
本文将系统讲清:
- 什么是 RTTI
- Class 对象的本质
- 类加载器的作用
- 双亲委派模型为什么存在
- JLS 与 JVMS 的区别
- 反射机制如何工作
这是一条完整的 JVM 认知路径。
一、什么是 RTTI(运行时类型识别)
RTTI(Run-Time Type Identification)表示:
程序在运行阶段可以知道对象的真实类型信息。
示例:
Animal animal = new Dog();
Class<?> clazz = animal.getClass();
System.out.println(clazz.getName());
输出:
com.xxx.Dog
说明:
即使变量声明类型是:
Animal
运行时 JVM 仍然知道对象真实类型是:
Dog
这就是 RTTI 的核心能力:
JVM 可以在运行期间识别对象的真实类型
典型应用场景:
- 反射
- 框架依赖注入(Spring)
- 序列化机制
- ORM 框架(MyBatis / Hibernate)
二、Class 对象的本质是什么?
理解一句话即可:
Class 对象就是类的运行时说明书
例如:
Class<?> clazz = Dog.class;
本质含义:
JVM 内部创建了一个对象:
Class<Dog>
它描述:
- 类名
- 方法列表
- 字段列表
- 构造方法
- 注解信息
- 父类信息
- 接口信息
结构如下:
Dog.class
↓
Class对象(类说明书)
↓
JVM依据说明书创建实例
关系:
Dog.class(说明书)
↓
new Dog()(实例)
三、静态变量的本质是什么?
理解 Class 对象后就可以理解:
static变量属于谁?
答案:
属于 Class 对象
示例:
class Dog {
static int count = 10;
}
本质结构:
Dog.class
├── 方法信息
├── 字段信息
└── static变量count
访问方式:
Dog.count
本质:
访问 Class对象中的变量
而不是实例变量。
四、Class 对象从哪里来?
答案:
来自 ClassLoader(类加载器)
执行流程:
.java源码
↓ 编译
.class字节码
↓ ClassLoader加载
Class对象
↓
new实例对象
关键点:
Class 对象不是程序员创建的,而是 JVM 创建的。
五、Class 对象生命周期
生命周期如下:
类加载 → 类验证 → 类准备 → 类解析 → 类初始化 → 使用 → 卸载
其中:
第一次主动使用类时触发加载,例如:
new对象
访问静态变量
调用静态方法
反射加载类
示例继承关系:
Animal
↓
Cat
↓
WhiteCat
加载顺序:
Animal.class
↓
Cat.class
↓
WhiteCat.class
原因:
JVM必须先加载父类才能加载子类
六、谁负责加载 Class 对象?
答案:
ClassLoader(类加载器)
职责:
.class文件
↓
加载进入JVM
↓
生成Class对象
注意:
.class 文件来源可以很多:
不仅来自:
磁盘
还可以来自:
网络
数据库
内存
动态生成
例如:
Spring AOP
就是动态生成字节码:
代理类.class
甚至:
运行时生成
运行时加载
七、什么是双亲委派模型?
类加载流程如下:
当前类加载器
↓
父类加载器
↓
爷爷加载器
↓
启动类加载器(Bootstrap)
流程规则:
先向上委托
再向下加载
执行逻辑:
父加载器能加载
↓
直接返回
父加载器不能加载
↓
子加载器加载
如果全部失败:
ClassNotFoundException
八、为什么必须使用双亲委派模型?
核心原因:
安全机制
示例:
假设你写:
java.lang.String
如果没有双亲委派:
可能加载你的类:
恶意String.class
结果:
整个 JVM 崩溃。
但实际上执行:
优先Bootstrap加载器加载JDK原生String
所以:
你的类不会被加载。
结论:
双亲委派机制保证:
核心API不可篡改
九、Java语言规范 与 JVM规范区别
Java体系包含两个规范:
1)Java语言规范(JLS)
作用:
规定:
.java文件怎么写
包括:
语法规则
关键字
变量声明方式
类结构
继承机制
接口机制
可以理解为:
Java语言宪法
2)Java虚拟机规范(JVMS)
作用:
规定:
.class文件结构
字节码格式
运行时行为
类加载机制
可以理解为:
JVM运行说明书
十、为什么要拆成两个规范?
目的:
实现:
语言 ≠ 虚拟机
结果:
JVM可以运行:
- Java
- Kotlin
- Groovy
- Scala
例如:
class Hello
编译后仍然是:
Hello.class
JVM只关心:
class文件
不关心:
源语言
十一、如何查看 .class 文件内容?
方式一:
javap -c Hello.class
输出:
字节码指令
例如:
aload_0
invokespecial
return
方式二:
可视化工具:
Classpy
适合初学者学习字节码结构。
十二、什么是反射(Reflection)?
Reflection 名字来源:
像镜子一样从对象反向获取类结构信息
正常方式:
类 → 创建对象
反射方式:
对象 → 获取类结构
所以叫:
Reflection(反射)
十三、反射机制可以做什么?
反射核心能力:
运行时操作类结构
包括:
1)动态创建对象
旧写法:
Class<?> clazz = Class.forName("com.example.User");
Object obj = clazz.newInstance();
推荐写法:
Object obj = clazz.getConstructor().newInstance();
原因:
newInstance() 已废弃
2)动态调用方法
示例:
Method method = clazz.getMethod("setName", String.class);
method.invoke(obj, "张三");
本质:
运行时执行方法
框架核心技术之一。
3)动态访问字段
示例:
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
String name = (String) field.get(obj);
作用:
打破封装访问private字段
Spring核心依赖能力之一。
例如:
@Autowired
底层就是:
反射注入
十四、总结:Java运行时机制全景图
完整关系如下:
.java源码
↓
编译
↓
.class字节码
↓
ClassLoader加载
↓
Class对象(类说明书)
↓
RTTI运行时识别类型
↓
Reflection反射操作类结构
理解这一整条链路,就真正进入了:
Java运行时世界的大门 🚀