Class.forName 动态加载类会触发其初始化并返回 Class 对象,用于获取字段、方法、注解等元数据;需确保全限定类名正确、类在 classpath 中且可被加载器访问。

通过 Class.forName 动态加载类,本质是触发类的**初始化(initialization)**,并返回其 Class 对象;有了这个对象,就能获取字段、方法、注解等运行时元数据。关键点在于:类必须在类路径(classpath)中,且加载器能访问到它。
确保类名正确且可被加载
Class.forName 接收的是**全限定类名(Fully Qualified Name)**,例如 "java.util.ArrayList" 或 "com.example.MyService"。注意:
- 不能用简单类名(如
"ArrayList")或内部类的简写(如"Outer$Inner"必须写全) - 如果类在模块中且未导出,或被封装(JDK 9+ 模块系统),可能抛
NoClassDefFoundError或IllegalAccessException - 默认使用当前线程上下文类加载器(
Thread.currentThread().getContextClassLoader()),若需指定加载器,用三参数重载:Class.forName(name, true, loader)
加载后立即获取基础元数据
拿到 Class 对象后,可直接调用其反射方法:
-
clazz.getSimpleName()→ 获取类名(不带包) -
clazz.getPackage()→ 获取包信息 -
clazz.getSuperclass()→ 获取父类 -
clazz.getInterfaces()→ 获取实现的接口数组 -
clazz.isInterface()、clazz.isEnum()、clazz.isAnnotation()→ 判断类型
例如:Class> c = Class.forName("java.time.LocalDate"); System.out.println(c.isEnum()); // false
读取注解与结构化元数据
若目标类、字段或方法上标注了 @Retention(RetentionPolicy.RUNTIME) 的注解,可通过反射读取:
-
clazz.getAnnotation(MyConfig.class)→ 获取类上的注解实例 -
clazz.getDeclaredFields()→ 获取所有字段(含 private),再对每个字段调用field.getAnnotation(NotNull.class) -
clazz.getDeclaredMethods()→ 获取所有方法,配合method.getParameterAnnotations()读取参数注解
注意:getDeclaredXXX 方法返回本类声明的成员(不继承),而 getXXX(无 declared)只返回 public 成员(含继承的)。
安全处理异常与常见陷阱
Class.forName 声明抛出 ClassNotFoundException,必须捕获或声明。另外需注意:
- 类加载会触发静态代码块执行 —— 若静态块有副作用(如初始化失败、依赖未就绪),会导致
ExceptionInInitializerError - 泛型信息在运行时被擦除,
clazz.getTypeParameters()只能拿到形参名(如"T"),无法获得实际类型 - 数组类型需特殊处理:
Class.forName("[Ljava.lang.String;")表示String[],也可用String[].class更直观

















