反射:Class 类
获取 Class 实例、类名、包信息、父类与接口信息
反射:Class 类
反射是 Java 在运行时探查和操作类的能力——你不需要在编译时就知道类名,可以在运行时动态加载、检查、调用任何类。Spring、MyBatis、JUnit 等框架都依赖反射实现"自动发现和注入"。
学完本章你将: 获取 Class 实例、探查类信息、分析继承关系。
什么是 Class 对象
JVM 每加载一个类,就会在内存中创建一个唯一的 Class 对象来描述这个类——它包含了类的所有元信息(类名、字段、方法、父类等)。获取这个 Class 对象,就等于拿到了操作这个类的"总钥匙"。
获取 Class 的三种方式
java
// 方式 1:类名.class —— 编译时已知类名(最常用)
Class<String> c1 = String.class;
// 方式 2:对象.getClass() —— 已有对象时
Class<?> c2 = "hello".getClass();
// 方式 3:Class.forName() —— 类名是运行时决定的字符串(框架最爱)
Class<?> c3 = Class.forName("java.lang.String");
// 三种方式拿到的是同一个 Class 对象!
System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true
💡 forName() 是框架的核心: Spring 在 XML 配置里写
class="com.example.MyService",就是通过Class.forName()加载的。类名存配置里,换实现只需改配置文件不用改代码。
探查类的基本信息
java
Class<?> clazz = Integer.class;
// 身份信息
clazz.getName(); // "java.lang.Integer"(全限定名)
clazz.getSimpleName(); // "Integer"(类名)
clazz.getPackageName(); // "java.lang"(包名)
// 类型判断
clazz.isInterface(); // false
clazz.isArray(); // false
clazz.isPrimitive(); // false(int.class 才是 true)
clazz.isEnum(); // false
// 访问修饰符
int mod = clazz.getModifiers();
Modifier.isPublic(mod); // true
Modifier.isFinal(mod); // true
Modifier.isAbstract(mod); // false
探查继承关系
java
Class<?> clazz = ArrayList.class;
// 向上走 —— 找父类
Class<?> parent = clazz.getSuperclass();
System.out.println(parent); // AbstractList(直接父类)
parent.getSuperclass(); // AbstractCollection(再上一级)
// 最终追溯到 Object,再往上是 null
// 横向看 —— 找实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
// [List, RandomAccess, Cloneable, Serializable, ...]
// 判断关系(比 instanceof 更灵活——不需要实例)
System.out.println(List.class.isAssignableFrom(ArrayList.class)); // true
// 问:List 这个类型能接受 ArrayList 吗?→ 能!
⚠️ isAssignableFrom vs instanceof:
A.class.isAssignableFrom(B.class)判断 A 是否是 B 的父类/接口(不需要实例)。b instanceof A判断对象 b 是否是 A 的实例(需要有对象)。