概述

由于Java泛型的引入,各种场景(虚拟机解析,反射等)下的方法调用都可能对原有的基础产生新的需求,如在泛型类中如何获取传入的参数化类型,因此,引入了诸如SignatureLocalVariableTypeTable等新的属性用于解决伴随泛型而来的参数识别问题。Signature是其中最重要的一项属性,他的作用就是存储一个方法字节码层次的特征签名,这个属性保存的参数类型并不是原生类型,而是包括了参数化(Parameterized Type)类型的信息。
另外。从Signature属性中,我们也可以得出结论,擦除法所谓的擦除:

  1. 方法中泛型在字节码进行擦除,泛型信息保存在Signature中。
  2. 元数据(类、属性、方法签名)还是保存了泛型信息。
  3. 如果泛型带有:extends XXX或super XXX ,擦除后的类型为XXX类型。

    反射获取元数据的泛型

  • 获取属性上的泛型类型:
    field.getGenericType();
  • 获取方法结构——形参的泛型类型:

    ParameterizedType parameterType = (ParameterizedType)method.getGenericParameterTypes()[0];
    parameterType.getActualTypeArguments()[0]

  • 获取方法结构——返回值的泛型类型:
    method.getGenericReturnType();

ParameterizedType returnType = (ParameterizedType) method.getGenericReturnType();
returnType.getActualTypeArguments()[0]

示例

  1. public class GenericType<T extends Number> {
  2. private T data;
  3. public <T extends Number> GenericType<T> apply(List<Long> list, Set<Double> set) {
  4. return null;
  5. }
  6. public static void main(String[] args) throws NoSuchMethodException {
  7. Class<?> clazz = GenericType.class;
  8. //获取类的属性字段
  9. Field[] declaredField = clazz.getDeclaredFields();
  10. //暴力解除,可以访问私有变量
  11. Field.setAccessible(declaredField, true);
  12. System.out.println("属性名\t参数类型\t\t参数泛型类型");
  13. for (Field field : declaredField) {
  14. String name = field.getName();
  15. Class<?> type = field.getType();
  16. Type genericType = field.getGenericType();
  17. System.out.println(name + "\t" + type + "\t" + genericType);
  18. }
  19. Method method = clazz.getDeclaredMethod("apply", new Class[]{List.class, Set.class});
  20. Type[] types = method.getGenericParameterTypes();
  21. System.out.println("方法形参的泛型类型\n");
  22. for (Type type : types) {
  23. ParameterizedType parameterType = (ParameterizedType) type;
  24. System.out.println(parameterType.getActualTypeArguments()[0]); //获取第一个
  25. }
  26. System.out.println("方法返回值的泛型类型");
  27. ParameterizedType returnType = (ParameterizedType) method.getGenericReturnType();
  28. System.out.println("泛型类型: " + returnType.getActualTypeArguments()[0]);
  29. System.out.println("RawType: " + returnType.getRawType());
  30. }

获取实参泛型类型

只能通过子类来获取传入父类的泛型参数
Type type = this.getClass().getGenericSuperclass();
Type type = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];

通过声明构造函数为protected,让外部类只能通过匿名类来创建,间接可以调用
Type type = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0] 并获取实际的泛型参数。

示例

  1. public class GenericType<T extends Number> {
  2. protected final Type type;
  3. protected GenericType(){
  4. System.out.println(this.getClass().getGenericSuperclass());
  5. Type superClass = getClass().getGenericSuperclass();
  6. Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
  7. this.type = type;
  8. }
  9. public <T extends Number> Collection<T> apply(List<T> list, Set<T> set) {
  10. List<T> container = new ArrayList<>(list);
  11. container.addAll(set);
  12. return container;
  13. }
  14. public static void main(String[] args) throws NoSuchMethodException {
  15. System.out.println("方法实参泛型类型");
  16. GenericType<Integer> subType = new GenericType<Integer>() {
  17. };
  18. System.out.println(subType);
  19. }
  20. }

image.png

Fastjson#TypeReference

  1. /**
  2. * Constructs a new type literal. Derives represented class from type
  3. * parameter.
  4. *
  5. * <p>Clients create an empty anonymous subclass. Doing so embeds the type
  6. * parameter in the anonymous class's type hierarchy so we can reconstitute it
  7. * at runtime despite erasure.
  8. */
  9. protected TypeReference(){
  10. Type superClass = getClass().getGenericSuperclass();
  11. Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
  12. Type cachedType = classTypeCache.get(type);
  13. if (cachedType == null) {
  14. classTypeCache.putIfAbsent(type, type);
  15. cachedType = classTypeCache.get(type);
  16. }
  17. this.type = cachedType;
  18. }

用法:

  1. Map<String, String> map = JSON.parseObject("json", new TypeReference<Map<String, String>>() {
  2. });
  3. JSONObject json = new JSONObject();
  4. GenericType gt = json.toJavaObject(new TypeReference<GenericType>() {
  5. });
  6. 其本质为:拿到类型Type
  7. public <T> T toJavaObject(TypeReference typeReference) {
  8. Type type = typeReference != null ? typeReference.getType() : null;
  9. return TypeUtils.cast(this, type, ParserConfig.getGlobalInstance());
  10. }

递归获取所有泛型

  1. public void show(Type type) {
  2. System.out.println("当前泛型: " + type);
  3. if (type instanceof ParameterizedType) {
  4. ParameterizedType pt = (ParameterizedType)type;
  5. System.out.println("RawType: " + pt.getRawType());
  6. Type[] ata = pt.getActualTypeArguments();
  7. System.out.println("ActualType: " + Arrays.toString(ata));
  8. for (Type t : ata) {
  9. show(t);
  10. }
  11. }
  12. }