我们创建的所有类class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例。注意,这里的Class类型是一个名叫Class的class,它的定义大致是这样的:
public final class Class {private Class() {}}
比如说现在JVM要加载字符串类,那么首先会创建一个Class的实例:Class cls = new Class(),cls中存储有String类型所有相关信息,比如名称、完整类名等等。而这个cls又作为静态变量赋值给class String(具体机制不明),所以我们可以通过String.class或者通过变量引用Class cls = String.class来获取字符串类型的所有class信息,这个通过class实例获取class信息的过程称为反射。
需要注意的是,上面的new Class()我们是无法使用的,因为它的构造方法是私有的(注意上面代码框),所以只有JVM可以创建Class实例。此外,上述过程对所有的类都适用,即使是我们自定义的类。同时,JVM对每一个类只会创建一个class实例(显然一个就够了)。
除了通过类型的静态变量.class外,还有以下方式获取类相应的Class实例:
- 如果已知一个类的实例:
String s = "Hello"; Class cls = s.getClass(); - 如果知道类的完整类名:
Class cls = Class.forName("java.lang.String");
典型示例:
# 获取Class实例的相关信息public static void main(String[] args) {printClassInfo("".getClass());printClassInfo(Runnable.class);printClassInfo(java.time.Month.class);printClassInfo(String[].class);printClassInfo(int.class);}static void printClassInfo(Class cls) {System.out.println("Class name: " + cls.getName());System.out.println("Simple name: " + cls.getSimpleName());if (cls.getPackage() != null) {System.out.println("Package name: " + cls.getPackage().getName());}System.out.println("is interface: " + cls.isInterface());System.out.println("is enum: " + cls.isEnum());System.out.println("is array: " + cls.isArray());System.out.println("is primitive: " + cls.isPrimitive());}}
# 获取字段public class Main {public static void main(String[] args) throws Exception {Class stdClass = Student.class;// 获取public字段"score":System.out.println(stdClass.getField("score"));// 获取继承的public字段"name":System.out.println(stdClass.getField("name"));// 获取private字段"grade":System.out.println(stdClass.getDeclaredField("grade"));}}class Student extends Person {public int score;private int grade;}class Person {public String name;}
