在 Java 中获取 Class
对象是反射机制的核心操作,以下是四种主要方式及其详细说明:
一、获取 Class 对象的四种方式
-
通过类字面常量(.class 语法)
Class<String> stringClass = String.class; // 引用类型 Class<Integer> intClass = int.class; // 基本类型
- 特点:
- 编译时安全(类名错误会导致编译失败)
- 不触发类初始化(静态代码块不会执行)
- 支持基本类型(如
int.class
)
- 特点:
-
通过对象的 getClass() 方法
String obj = "Hello"; Class<?> clazz = obj.getClass(); // 返回 java.lang.String
- 特点:
- 需要已有对象实例
- 返回对象的运行时类型(可能被子类覆盖)
- 特点:
-
通过 Class.forName() 静态方法
Class<?> clazz = Class.forName("java.lang.String"); // 需全限定类名
- 特点:
- 动态加载类(类名可来自配置文件/数据库)
- 触发类初始化(执行静态代码块)
- 需处理
ClassNotFoundException
- 特点:
-
通过类加载器的 loadClass() 方法
ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class<?> clazz = loader.loadClass("java.lang.String");
- 特点:
- 不触发类初始化(静态代码块不执行)
- 可指定自定义类加载器
- 需处理
ClassNotFoundException
- 特点:
二、关键区别总结
方式 | 是否需要实例 | 是否触发初始化 | 适用场景 |
---|---|---|---|
类名.class | 否 | 否 | 编译时已知类名 |
对象.getClass() | 是 | 是(已初始化) | 已有对象实例 |
Class.forName() | 否 | 是 | 动态加载类(如 JDBC 驱动) |
ClassLoader.loadClass() | 否 | 否 | 避免初始化副作用 |
三、使用示例
public class Demo {
static {
System.out.println("静态代码块执行"); // 类初始化标记
}
public static void main(String[] args) throws Exception {
// 方式1:不触发初始化
Class<?> clazz1 = Demo.class; // 无输出
// 方式2:需对象实例(已初始化)
Demo obj = new Demo();
Class<?> clazz2 = obj.getClass(); // 无新输出
// 方式3:触发初始化
Class<?> clazz3 = Class.forName("Demo"); // 输出"静态代码块执行"
// 方式4:不触发初始化
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> clazz4 = loader.loadClass("Demo"); // 无输出
}
}
四、应用场景建议
- 框架开发:优先用
Class.forName()
实现动态加载(如 Spring 容器) - 性能优化:缓存
类名.class
避免重复查找 - 避免初始化副作用:使用
ClassLoader.loadClass()
(如热部署场景)
相关问题
- 反射获取
Class
对象时,类初始化阶段会发生什么? - 如何通过反射获取数组类型的
Class
对象(如String[].class
)? - 不同类加载器加载的同一个类,其
Class
对象是否相同?
-
: 通过类字面常量获取 Class 对象不会触发初始化
- Class.forName 会触发类初始化
- 类加载器方式提供更细粒度的控制
- 动态加载是反射的核心应用场景