Class对象是堆中Java层可操作的元数据“视图”,类元数据是JVM在元空间中存储的真实C++结构;二者为“镜像与本体”关系,Class对象通过\_java\_mirror指向instanceKlass,不存原始信息,仅作访问入口。

Class对象是Java层可操作的元数据“视图”,类元数据是JVM内部存储在元空间的真实结构;二者不是同一东西,而是“镜像与本体”的关系。
Class对象是堆里的Java对象,不是类元数据本身
你调用 String.class 或 obj.getClass() 得到的,是一个存放在Java堆中的 java.lang.Class 实例——它本身是个普通对象,有对象头、实例数据、对齐填充。这个对象由JVM在类加载时自动创建,内部通过一个隐藏字段(_java_mirror)指向真正的类元数据结构(HotSpot里的 instanceKlass)。所以:
• Class 对象可以被GC回收(当类卸载且无强引用时);
• 它不直接存字段名、方法签名等原始信息,只是访问入口;
• 你不能通过 new Class() 创建它,JVM禁止用户手动实例化。
类元数据存在元空间,包含编译期确定的全部结构信息
类元数据是JVM加载 .class 文件后,在元空间(Metaspace)中构建的一组C++级数据结构(如 instanceKlass),包括:
• 运行时常量池(符号引用、字符串字面量索引);
• 字段表(偏移量、类型描述符、访问标志);
• 方法表(字节码、栈帧大小、局部变量表);
• 父类/接口指针、注解的二进制字节流等。
这些内容不可被Java代码直接读写,也不受GC管理(元空间内存由本地内存分配,仅随类卸载释放)。Class 对象的方法如 getDeclaredMethods(),本质是调用JVM内部的 instanceKlass::methods() 接口,把底层数据“翻译”成 Method 对象返回。
反射调用时,两者协作但角色分明
当你执行 method.invoke(obj, args):
• method 是 java.lang.reflect.Method 实例,它缓存了对 instanceKlass 中对应方法入口的引用;
• 实际调用会穿过JNI进入JVM native 层,最终跳转到该方法的字节码或JIT编译后的机器码地址;
• Class 对象只负责提供查找路径(比如按名字+参数类型匹配),不参与执行;
• 如果方法是私有的,setAccessible(true) 修改的是JVM对该方法的访问检查标记,不是改 Class 对象的字段。
容易忽略的一点:JDK 9+ 模块系统下,跨模块反射非开放包(如 sun.misc.Unsafe)会直接失败,报 InaccessibleObjectException——这不是 Class 对象的问题,而是JVM在元数据层面就拒绝建立访问链路。这时候再怎么缓存 Method 或调 setAccessible 都无效。


















