当我们在代码中使用反射时,肯定会用到Class实例,那么大家有没有想过,这究竟是什么东西呢?跟类的元数据有什么区别?
在Java虚拟机(JVM)中,类的元数据和堆中的Class
实例是两个不同的概念,它们在JVM中扮演着不同的角色。
先来一个高度概括:方法区的类元数据提供了类的定义信息,是JVM在内部使用的,而堆中的Class
实例则是Java程序可以通过代码直接操作的对象,两者共同支持了Java强大的运行时反射能力。
方法区的Class元数据
类元数据为JVM执行代码提供了必要的信息,包括类型检查、访问控制、编译优化、动态链接、反射操作等。
存储位置:类元数据存储在方法区(在JDK 8及之后的版本中,这一部分称为元空间)。
方法区是JVM的一个逻辑部分,用于存储已被虚拟机加载的类元信息、常量、静态变量、即时编译器编译后的代码等。
内容:类元数据包括类的结构信息(如字段、方法、构造函数、接口信息)、访问标志(如是否为abstract
、final
等)、类加载器信息、运行时常量池等。这些信息主要是从对应的.class
文件中解析而来。
堆中的Class实例
Class
对象使得程序能够在运行时利用反射进行动态操作,如动态创建对象、调用方法、访问字段等。它是Java反射API的基础。
存储位置:堆中的Class
实例存储在Java堆内存中,这是JVM用于存放所有Java对象的部分。
作用:每个被加载的类在JVM中都有一个java.lang.Class
对象的实例,这个实例代表了那个类本身。
内容:Class
实例包含了关于类的元数据的引用,并能通过反射API访问类的元数据。例如,可以通过一个Class
实例来获取类的名称、其父类、实现的接口、方法、字段等信息。
图片来源:JVM速成手册#了加载机制篇
关系
依赖关系:堆中的Class
实例依赖于方法区的类元数据来获取类型相关信息。实际上,Class
对象就是方法区中类元数据的一种“面向用户”的表现形式,使得程序员可以在Java代码中操作和查询类信息。
生命周期:方法区的类元数据的生命周期通常依赖于类加载器;当类加载器被回收时,该加载器加载的所有类的元数据也将被回收。相比之下,Class
实例在堆中的生命周期则依赖于是否还有引用指向它,如其他类或类加载器持有Class
对象的引用。