0%

Java 反射(三):反射与泛型

1. 反射与泛型的关系是

  • 泛型参数在运行时会被删除
  • 但在类信息 Class依然有关于泛型的一些信息,可以通过反射得到

2. 反射中可以获取与泛型信息的方法有

  • Class: public TypeVariable<Class<T>>[] getTypeParameters() //获取类的泛型参数信息

  • Field:public Type getGenericType()

  • Method

    • public Type getGenericReturnType()
    • public Type[] getGenericParameterTypes()
    • public Type[] getGenericExceptionTypes()
  • Constructor: public Type[] getGenericParameterTypes()

  • Type 是一个接口,Class 实现了 TypeType 的其他子接口还有

    • TypeVariable:类型参数,可以有上界,比如:T extends Number
    • ParameterizedType:参数化的类型,有原始类型和具体的类型参数,比如:List<String>
    • WildcardType:通配符类型,比如:?? extends Number? super Integer

3. 写一个通过反射获取泛型信息的 Demo

  • Demo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public class GenericDemo {
    static class GenericTest<U extends Comparable<U>, V> {
    U u;
    V v;
    List<String> list;
    public U test(List<? extends Number> number) {
    return null;
    }
    }
    public static void main(String[] args) throws Exception {
    Class<?> cls = GenericTest.class;
    //类的类型参数
    for(TypeVariable t : cls.getTypeParameters()) {
    System.out.println(t.getName() + " extends " + Arrays.toString(t.getBounds()));
    }
    //字段:泛型类型
    Field fu = cls.getDeclaredField("u");
    System.out.println(fu.getGenericType());
    //字段:参数化的类型
    Field flist = cls.getDeclaredField("list");
    Type listType = flist.getGenericType();
    if(listType instanceof ParameterizedType) {
    ParameterizedType pType = (ParameterizedType) listType;
    System.out.println("raw type: " + pType.getRawType() + ", type arguments: " + Arrays.toString(pType.getActualTypedArguments()));
    }
    //方法的泛型参数
    Method m = cls.getMethod("test", new Class[] { List.class });
    for(Type t : m.getGenericParameterTypes()) {
    System.out.println(t);
    }
    }
    }
  • 输出

    1
    2
    3
    4
    5
    U extends [java.lang.Comparable<U>]
    V extends [class java.lang.Object]
    U
    raw type: interface java.util.List, tye arguments: [class java.lang.String]
    java.util.List<? extends java.lang.Number>

4. 反射虽然是灵活的,但一般情况下,并不是我们优先建议的,为什么

  • 反射更容易出现运行时错误。使用显示的类和接口,编译器能帮我们做类型检查,减少错误;但使用反射,类型是运行时才知道的,编译器无能为力
  • 反射的性能要低一些,在访问字段、调用方法前,反射先要查找对应的 Field/Method,要慢一些
  • 简单地说,如果能用接口实现同样的灵活性,就不要使用反射
-------------------- 本文结束感谢您的阅读 --------------------