Java反射机制的核心起点是获取Class对象,三种方式分别为:类名.class(编译期确定、不触发初始化)、对象.getClass()(运行时获取实际类型、支持多态)、Class.forName("全限定名")(动态加载并执行静态初始化)。
Java 反射机制的核心起点,就是拿到一个类的 Class 对象。它不是普通类的实例,而是 JVM 为每个已加载类在元空间中生成的“结构说明书”。没有它,后续所有动态创建对象、调用方法、访问字段的操作都无从谈起。而动态加载的关键,也正始于如何在运行时拿到这个 Class 对象——类名甚至可能来自配置文件或用户输入。
无论目标类是否已实例化、是否在编译期可见,这三种方式覆盖了绝大多数场景,本质都是指向同一个 Class 实例(JVM 中唯一):
Student.class,不触发类初始化,也不抛异常。new Student().getClass() 返回的就是 Student 的 Class 对象。ClassNotFoundException。拿到 Class 对象只是第一步,真正实现“运行时决定用哪个类”,还需完成实例化与方法调用:
clazz.getDeclaredConstructor(...).setAccessible(true).newInstance(...) 可绕过访问控制,调用私有构造器;clazz.getMethod("methodName", paramTypes) 或 getDeclaredMethod 获取 Method 对象;invoke 的第一个参数传 null;实例方法则传具体对象;setAccessible(true) 才能成功执行。反射虽灵活,但容易踩坑,几个常见注意事项要牢记:
立即学习“Java免费学习笔记(深入)”;
int.class)、void 都有对应的 Class 对象,不能只关注普通类;List<String>.class 实际等价于 List.class;setAccessible(true) 可能被拒绝,生产环境需评估权限策略。Spring 的 Bean 初始化、MyBatis 的 SQL 映射绑定、JUnit 的测试方法扫描——它们都不在编译期硬编码类名和方法名。而是靠读取注解、XML 或配置项,再用反射动态加载类、注入属性、调用回调。这种解耦让框架具备高度可扩展性:你写个新 Service,加个 @Service,它就被自动发现并管理,背后全是 Class 对象 + 反射在工作。