我们可以通过不同的方式获取 Class 对象,具体取决于你的需求。

获取原始类型 的 Class 对象
这是最简单、最直接的方式,原始类型就是泛型被擦除后剩下的类型。
对于 List<String>,其原始类型是 List。
import java.util.List;
public class GetRawClassExample {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
// 获取 List<String> 的原始类型 Class 对象
// listClass 实际上是 List.class
Class<?> listClass = stringList.getClass();
System.out.println("原始类型 Class 对象: " + listClass);
System.out.println("它是否等于 List.class? " + (listClass == List.class)); // true
// 对于 Map<Integer, String>,原始类型是 Map
Map<Integer, String> integerStringMap = new HashMap<>();
Class<?> mapClass = integerStringMap.getClass();
System.out.println("Map 的原始类型 Class 对象: " + mapClass);
System.out.println("它是否等于 Map.class? " + (mapClass == Map.class)); // true
}
}
任何泛型实例(如 new ArrayList<String>())的 getClass() 方法返回的都是其原始类型(ArrayList.class)的 Class 对象,类型参数(如 String)在运行时已经不存在了。
获取泛型类型参数 的 Class 对象(关键问题)
这是开发者最常遇到的需求,既然 getClass() 直接获取原始类型,我们该如何获取 List<String> 中的 String 的 Class 对象呢?

答案是:在运行时,你无法从一个泛型实例(list 对象)本身直接获取其类型参数。
你可以在编译时通过方法参数传递类型信息,或者在定义类时通过反射来获取。
通过方法参数传递类型信息(最常用)
这是解决此问题的标准模式,你可以创建一个方法,该方法接收一个 Class 对象作为参数,这个 Class 对象代表了类型参数。
import java.util.List;
public class GetGenericTypeClassExample {
// 泛型方法,可以接受任何类型的 List
public static <T> void processList(List<T> list, Class<T> elementType) {
System.out.println("正在处理 List,其元素类型是: " + elementType.getName());
// 你可以使用 elementType 来创建该类型的实例
try {
T instance = elementType.getDeclaredConstructor().newInstance();
System.out.println("成功创建了一个 " + instance.getClass().getSimpleName() + " 实例。");
} catch (Exception e) {
System.out.println("无法创建 " + elementType.getName() + " 的实例。");
}
}
public static void main(String[] args) {
List<String> stringList = Arrays.asList("Hello", "Generics");
List<Integer> integerList = Arrays.asList(1, 2, 3);
// 调用时,显式地传入 String.class 和 Integer.class
processList(stringList, String.class);
processList(integerList, Integer.class);
}
}
输出:

正在处理 List,其元素类型是: java.lang.String
成功创建了一个 String 实例。
正在处理 List,其元素类型是: java.lang.Integer
成功创建了一个 Integer 实例。
优点:
- 类型安全,在编译时就能检查。
- 代码清晰,意图明确。
通过反射获取类定义上的泛型信息(高级用法)
如果你有一个 Class 对象,并且这个类本身是泛型化的(比如一个接口或抽象类),你可以通过反射来获取其父类或接口上的泛型类型信息。
假设有一个泛型接口 DataProcessor<T>
// 泛型接口
interface DataProcessor<T> {
void process(T data);
}
// 实现类,指定 T 为 String
class StringDataProcessor implements DataProcessor<String> {
@Override
public void process(String data) {
System.out.println("处理字符串: " + data);
}
}
我们想通过 StringDataProcessor.class 这个 Class 对象,反推出它实现的 DataProcessor 接口的泛型参数是 String。
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ReflectionGenericTypeExample {
public static void main(String[] args) {
// 获取实现类的 Class 对象
Class<?> processorClass = StringDataProcessor.class;
// 获取它直接实现的接口
Type[] interfaces = processorClass.getGenericInterfaces();
for (Type type : interfaces) {
// 检查是否是参数化类型(即泛型)
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
// 获取原始类型(DataProcessor.class)
System.out.println("原始类型: " + pType.getRawType());
// 获取类型参数(String.class)
Type[] typeArgs = pType.getActualTypeArguments();
for (Type typeArg : typeArgs) {
// 对于这个例子,typeArg 会返回 Class 对象
System.out.println("类型参数: " + typeArg.getTypeName());
// typeArg 是 Class,可以强制转换
if (typeArg instanceof Class) {
Class<?> argClass = (Class<?>) typeArg;
System.out.println("类型参数的 Class 对象: " + argClass);
}
}
}
}
}
}
输出:
原始类型: interface DataProcessor
类型参数: java.lang.String
类型参数的 Class 对象: class java.lang.String
注意:
- 这种方法依赖于
Class对象本身的元数据(即类定义)。 - 它不能从一个实例(如
new StringDataProcessor())获取信息,必须从Class对象(如StringDataProcessor.class)获取。 - 对于复杂的继承链,解析起来会更复杂。
| 场景 | 目标 | 解决方案 | 示例 |
|---|---|---|---|
| 获取泛型实例的类型 | 获取原始类型的 Class |
直接调用实例的 getClass() 方法。 |
list.getClass() 得到 ArrayList.class |
获取类型参数的 Class |
获取 List<T> 中 T 的 Class |
方法1(推荐): 使用泛型方法,显式传入 T.class。 |
processList(list, String.class) |
| 获取类定义上的泛型信息 | 获取类实现的泛型接口/父类的参数 | 方法2(高级): 使用反射解析 Class 对象的 getGenericInterfaces() 或 getGenericSuperclass()。 |
StringDataProcessor.class.getGenericInterfaces() |
对于绝大多数应用开发场景,方法一(通过方法参数传递) 是最实用、最清晰、最安全的选择,方法二(反射)通常用于框架、库开发等需要动态分析类结构的底层代码中。
