Java泛型类型变量TypeVariable接口了解一下!

内容分享2小时前发布
0 0 0

它是 Java 反射 API 中的一个核心接口,用于表明泛型类型变量,例如在泛型类、泛型方法中声明的 <T>、<E>、<K, V> 中的 T、E、K、V 等。


一、官方定义

public interface TypeVariable<D extends GenericDeclaration> extends Type {
    Type[] getBounds();           // 获取上界(如 T extends Number → [Number.class])
    D getGenericDeclaration();    // 获取声明此类型变量的“泛型声明”(类/方法/构造器)
    String getName();             // 获取变量名,如 "T", "E"
}

二、核心概念解析

1. 什么是 TypeVariable?

  • 它代表的是你在代码中写的 <T>、<E> 这种类型参数(Type Parameter)
  • 不是具体类型,而是一个“占位符”,在编译时被擦除,在运行时通过反射可获取其元信息。
  • 它只能出目前泛型定义中:
    • 泛型类:class Box<T> { … }
    • 泛型方法:public <T> T get() { … }
    • 泛型构造器:public <T> MyClass(T t) { … }

2. 三个核心方法详解

String getName()

返回类型变量的名字:

class Pair<K, V> { ... }

TypeVariable<?>[] tvs = Pair.class.getTypeParameters();
System.out.println(tvs[0].getName()); // K
System.out.println(tvs[1].getName()); // V

Type[] getBounds()

返回类型变量的上界(支持多重边界):

class Box<T extends Number & Comparable<T>> { ... }

TypeVariable<?> tv = Box.class.getTypeParameters()[0];
Type[] bounds = tv.getBounds();
// bounds[0] → Number (Class)
// bounds[1] → Comparable<T> (ParameterizedType)

⚠️ 注意:

  • 如果没有显式写 extends,默认上界是 Object。
  • 边界可能是 Class、ParameterizedType、甚至另一个 TypeVariable。

D getGenericDeclaration()

返回声明这个类型变量的“泛型声明体”:

  • 如果是类泛型 → 返回 Class<?>
  • 如果是方法泛型 → 返回 Method
  • 如果是构造器泛型 → 返回 Constructor<?>
public class Test {
    public <T extends String> void method(T t) { }
}

Method method = Test.class.getMethod("method", String.class);
TypeVariable<Method> tv = method.getTypeParameters()[0];
Method declaringMethod = tv.getGenericDeclaration(); // 就是 method 本身

三、TypeVariable 出现场景

场景 1:从泛型类获取

class Container<T extends Number> { }

TypeVariable<?>[] tvs = Container.class.getTypeParameters();
for (TypeVariable<?> tv : tvs) {
    System.out.println(tv.getName() + " extends " + Arrays.toString(tv.getBounds()));
}
// 输出: T extends [class java.lang.Number]

场景 2:从泛型方法获取

public <E extends Exception> void handle(E e) throws E { }

Method method = ...;
TypeVariable<Method> tv = method.getTypeParameters()[0];
System.out.println(tv.getName()); // E
System.out.println(Arrays.toString(tv.getBounds())); // [class java.lang.Exception]

四、重大注意事项

1. TypeVariable ≠ 具体类型

不能通过 TypeVariable 获取 Class<T>,由于:

  • T 可能是 ? extends Number,没有具体类;
  • T 可能是另一个 TypeVariable;
  • T 可能是 ParameterizedType(如 Comparable<T>);

✅ 正确做法:递归解析边界,或结合子类实际类型推断(如 Spring、MyBatis 所做)。


2. 类型擦除不影响反射元数据

虽然 JVM 运行时擦除泛型,但 .class 文件中保留了 Signature 属性,可通过反射读取:

// 即使运行时是 Object,反射仍能拿到 T 的定义
Field field = ...;
Type type = field.getGenericType(); // 可能是 TypeVariable
© 版权声明

相关文章

暂无评论

none
暂无评论...