java泛型探究

介绍

泛型是java1.5引入的新特性, 泛型的引入主要是为了提高 Java 编程语言的类型安全性和代码重用性,具体意义包括:

  1. 类型安全

• 泛型在编译时提供了类型检查,确保在使用集合或其他数据结构时,传入的类型是正确的。这可以有效减少运行时类型转换错误,提高代码的安全性。

  1. 消除强制类型转换

• 使用泛型可以避免在从集合中取出元素时需要进行强制类型转换。例如,使用 List<String> 时,取出元素不需要强制转换为 String 类型,直接使用即可。这使得代码更简洁、可读性更强。

  1. 增强代码的可重用性

• 泛型允许开发者编写与类型无关的代码,从而实现更高的代码重用性。一个使用泛型的类或方法可以适用于多种数据类型,而无需为每种数据类型编写重复的代码。

  1. 提升可维护性

• 由于类型安全和简化的代码结构,使用泛型的代码更容易理解和维护。当出现问题时,编译器可以提供更好的错误信息,使得调试和修复变得更加简单。

注意事项

类型擦除

例如

@Test
void instanceofTest() {
    List<String> list = new ArrayList<>();
    if (list instanceof ArrayList) {
        System.out.println("list is an instance of ArrayList");
    }
    // 会报错
    if (list instanceof List<String>) {
        System.out.println("list is a List<String>");
    }

    if (list instanceof List<?>) {
        System.out.println("list is a List<?>");
    }

    if (list instanceof List) {
        System.out.println("list is a List");
    }
}

其中代码list instanceof List<String>会报错。 Java 的泛型在编译时会进行类型擦除,即在生成字节码时,泛型类型参数会被移除,替换为对应的原始类型(如 List<T> 会被擦除为 List)。因此,在运行时泛型的具体类型信息不存在,只保留了原始类型。这意味着无法使用 instanceof 来检查泛型类型的具体参数(例如 List<String>),因为在运行时这些参数已经被擦除,List<String> 和 List<Integer> 都被视为相同的 List 类型。

我们看一下其它三个的擦除效果

@Test
void instanceofTest() {
    List<String> list = new ArrayList();
    if (list instanceof ArrayList) {
        System.out.println("list is an instance of ArrayList");
     }

     if (list instanceof List) {
        System.out.println("list is a List<?>");
     }

     if (list instanceof List) {
        System.out.println("list is a List");
     }
}

小结

• instanceof List<?> 合法,因为它不涉及对具体元素类型的检查,只是检查列表本身的类型。这与 instanceof List 是等效的。

• instanceof List<String> 会报错,因为编译器不允许检查带有具体类型参数的泛型类型,防止类型擦除后产生的错误和误导。

但是java16之后list instanceof List<String>这种也是支持的了

举个例子说明一下泛型的编译时擦除

public class Demo1<T extends Number> {

    private T value;

    public Demo1(T t) {
        this.value = t;
    }

    public static void main(String[] args) {

        Demo1<Number> intInstance = new Demo1<Number>(42);
        Demo1<Double> doubleInstance = new Demo1<>(3.14);
        System.out.println(intInstance.getClass() == doubleInstance.getClass()); // 输出 true
        // 获取字段的运行时类型
        Field field;
        try {
            field = Demo1.class.getDeclaredField("value");
            System.out.println("运行时字段类型: " + field.getType().getName());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

先用idea查看编译后的class代码

public class Demo1<T extends Number> {
    private T value;

    public Demo1(T t) {
        this.value = t;
    }

    public static void main(String[] args) {
        Demo1<Number> intInstance = new Demo1(42);
        Demo1<Double> doubleInstance = new Demo1(3.14);
        System.out.println(intInstance.getClass() == doubleInstance.getClass());

        try {
            Field field = Demo1.class.getDeclaredField("value");
            System.out.println("运行时字段类型: " + field.getType().getName());
        } catch (NoSuchFieldException var5) {
            var5.printStackTrace();
        }

    }
}

只有这两句代码有变化

// 编译前
Demo1<Number> intInstance = new Demo1<Number>(42);
Demo1<Double> doubleInstance = new Demo1<>(3.14);

// 编译后
Demo1<Number> intInstance = new Demo1(42);
Demo1<Double> doubleInstance = new Demo1(3.14);

属性private T value;和临时变量Demo1<Number> intInstance都没变, 这里和idea有关系, 具体可以查看 为啥用IDEA反编译没有擦除泛型?
接下来看一下反编译的代码javap -c -v Demo1

public class per.qiao.myutils.generic.genericerase.Demo1<T extends java.lang.Number> extends java.lang.Object
  minor version: 0
  major version: 61
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
 // ... 省略类常量池部分
#1 = Methodref          #2.#3         // java/lang/Object."<init>":()V 父类无参构造器(Object)
#7 = Fieldref           #8.#9         // value字段
#8 = Class              #10           // per/qiao/myutils/generic/genericerase/Demo1  value的引用
#9 = NameAndType        #11:#12       // value:Ljava/lang/Number;  value的类型
#10 = Utf8               per/qiao/myutils/generic/genericerase/Demo1
#11 = Utf8               value
#12 = Utf8               Ljava/lang/Number;
#19 = Methodref          #8.#20        // per/qiao/myutils/generic/genericerase/Demo1."<init>":(Ljava/lang/Number;)V

per/qiao/myutils/generic/genericerase/Demo1.value:Ljava/lang/Number;  //value字段
{
  // 构造器部分
  public per.qiao.myutils.generic.genericerase.Demo1(T);	// 构造方法签名
    descriptor: (Ljava/lang/Number;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V 父类构造器
         4: aload_0
         5: aload_1
         6: putfield      #7                  // Field value:Ljava/lang/Number;
         9: return
      LineNumberTable:
        line 14: 0
        line 15: 4
        line 16: 9
      LocalVariableTable:	// 构造器方法变量
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lper/qiao/myutils/generic/genericerase/Demo1;
            0      10     1     t   Ljava/lang/Number;
      LocalVariableTypeTable:	// 构造器方法泛型变量
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lper/qiao/myutils/generic/genericerase/Demo1<TT;>;
            0      10     1     t   TT;
    MethodParameters:
      Name                           Flags
      t
    Signature: #84                          // (TT;)V

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=5, args_size=1
         0: new           #8                  // class per/qiao/myutils/generic/genericerase/Demo1
         3: dup
         4: bipush        42
         6: invokestatic  #13                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         9: invokespecial #19                 // Method "<init>":(Ljava/lang/Number;)V
        12: astore_1
        13: new           #8                  // class per/qiao/myutils/generic/genericerase/Demo1
        16: dup
        17: ldc2_w        #22                 // double 3.14d
        20: invokestatic  #24                 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
        23: invokespecial #19                 // Method "<init>":(Ljava/lang/Number;)V
        26: astore_2
  		// ...省略部分代码部分
      LineNumberTable:
        // ...省略行记录
      LocalVariableTable:	// 方法变量表
        Start  Length  Slot  Name   Signature
           57      21     3 field   Ljava/lang/reflect/Field;
           80       5     4     e   Ljava/lang/NoSuchFieldException;
            0      86     0  args   [Ljava/lang/String;
           13      73     1 intInstance   Lper/qiao/myutils/generic/genericerase/Demo1;
           27      59     2 doubleInstance   Lper/qiao/myutils/generic/genericerase/Demo1;
      LocalVariableTypeTable:	// 方法泛型表
        Start  Length  Slot  Name   Signature
           13      73     1 intInstance   Lper/qiao/myutils/generic/genericerase/Demo1<Ljava/lang/Number;>;
           27      59     2 doubleInstance   Lper/qiao/myutils/generic/genericerase/Demo1<Ljava/lang/Double;>;
     // ... 省略其它类信息
}

其中Constant pool是常量池部分, 已忽略

构造器泛型擦除

public per.qiao.myutils.generic.genericerase.Demo1(T);	// 构造方法签名
    descriptor: (Ljava/lang/Number;)V	// 描述符信息。
        

Ljava/lang/Number;:表示构造方法接收的参数类型是 Number。V:表示方法返回类型是 void,构造方法没有返回值

这是构造方法的签名,表示这是 Demo1 类的构造方法,接受一个类型为 T 的参数(在字节码中,T 实际上是 Number 类型,泛型在编译时已经擦除为它的上界 Number)

字段擦除private T value;

code部分:
   putfield      #7                  // Field value:Ljava/lang/Number;
对应的常量池部分:
#7 = Fieldref           #8.#9         // value字段
#8 = Class              #10           // per/qiao/myutils/generic/genericerase/Demo1  value的引用
#9 = NameAndType        #11:#12       // value:Ljava/lang/Number;  value的类型
#10 = Utf8               per/qiao/myutils/generic/genericerase/Demo1
#11 = Utf8               value
#12 = Utf8               Ljava/lang/Number;

我们看到字段value的定义部分是#7, 它是一个字段引用, 对应的是#8.#9 也就是per/qiao/myutils/generic/genericerase/Demo1.Ljava/lang/Number ,简写就是 Demo1.Number

#7 = #8.#9 = #10.#11:#12 = per/qiao/myutils/generic/genericerase/Demo1.value:Ljava/lang/Number 简写就是 Demo1.value:Number 所以private T value;编译后经泛型擦除后就变成了Demo1.value:Number

对象中的擦除

// 源代码
Demo1<Number> intInstance = new Demo1<Number>(42);
Demo1<Double> doubleInstance = new Demo1<>(3.14);

// 编译后
Demo1<Number> intInstance = new Demo1(42);
Demo1<Double> doubleInstance = new Demo1(3.14);

// 反编译后
// LocalVariableTable 本地变量表
intInstance   Lper/qiao/myutils/generic/genericerase/Demo1;
doubleInstance   Lper/qiao/myutils/generic/genericerase/Demo1;

// LocalVariableTypeTable 本地泛型变量表
intInstance   Lper/qiao/myutils/generic/genericerase/Demo1<Ljava/lang/Number;>;
doubleInstance   Lper/qiao/myutils/generic/genericerase/Demo1<Ljava/lang/Double;>;

从反编译后的信息可以看出, 经泛型擦除后Demo1<Number> intInstanceDemo1<Double> doubleInstance都变成了Lper/qiao/myutils/generic/genericerase/Demo1也就是Demo1类型

我们再看一下这句代码Demo1<Number> intInstance = new Demo1<Number>(42);

 0: new           #8                  // class per/qiao/myutils/generic/genericerase/Demo1
 3: dup
 4: bipush        42
 6: invokestatic  #13                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
 9: invokespecial #19                 // Method "<init>":(Ljava/lang/Number;)V

实际上是如下代码

Demo1 intInstance = new Demo1(Integer.valueOf(42)); 

最后一行可以看出是调用的Demo1的参数为Number的构造器; 其中常量#19如下

#19 = Methodref          #8.#20        // per/qiao/myutils/generic/genericerase/Demo1."<init>":(Ljava/lang/Number;)V
#8 = Class              #10           // per/qiao/myutils/generic/genericerase/Demo1
#10 = Utf8               per/qiao/myutils/generic/genericerase/Demo1
#20 = NameAndType        #5:#21        // "<init>":(Ljava/lang/Number;)V
#5 = Utf8               <init>
#21 = Utf8               (Ljava/lang/Number;)V

翻译一下

#8.#20 = #10.#20 = #10.#5:#21 = per/qiao/myutils/generic/genericerase/Demo1.<init>:(Ljava/lang/Number;)V

再翻译一下就是调用构造器 public Demo1(Number t)

小结

泛型是在编译时进行擦除动作, 当泛型有上边界时, 泛型会被上边界类型代替, 否则都会被代替成Object类型, 所以泛型也存在反射使用时的安全问题, 由于篇幅问题, 这个点读者自己去查相关资料, 泛型只是提供了编译时的安全监测

泛型的继承问题

桥方法的来由…

public interface GenericInterface<T> {
    void say(T t);
}

public class SubClass implements GenericInterface<String> {
    @Override
    public void say(String s) {

    }
}

大家都知道java中有个规定子类实现覆写父类的方法需要方法签名都相同, 由于泛型的擦除问题, 当父类的void say(T t);擦除后,会变成void say(Object t);那么子类的方法public void say(String s) 是具体类型不会被擦除, 那么实际就违背了覆写的概念, 因为它两的方法签名不同了(参数是签名中的部分,返回值才不是), 那么java真的会自己打自己的脸吗? 下面跟着我探究原理

编译后的代码看不出什么, 直接跳过

javap -c -v SubClass

反编译后的代码如下(省略了一些代码)

public class per.qiao.myutils.generic.genericerase.SubClass implements per.qiao.myutils.generic.genericerase.GenericInterface<java.lang.String> {
  public void say(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=2, args_size=2
         0: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  this   Lper/qiao/myutils/generic/genericerase/SubClass;
            0       1     1     s   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      s

  public void say(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: checkcast     #7                  // class java/lang/String
         5: invokevirtual #9                  // Method say:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lper/qiao/myutils/generic/genericerase/SubClass;
    MethodParameters:
      Name                           Flags
      s                              synthetic
}

我们看到有两个say方法,一个方法签名是public void say(java.lang.String)还有一个是public void say(java.lang.Object), 很显然第二个是覆写的接口中的方法, 而且该方法中有这句命令invokevirtual #9,看注释Method say:(Ljava/lang/String;)V就是调用的当前类的public void say(java.lang.String)方法, 再看一下方法标签flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC 可以知道这是一个动态生成的(ACC_SYNTHETIC)桥接方法(ACC_BRIDGE)

==所以当我们继承父类泛型方法的时候, 子类会自动生成一个桥接方法来覆盖父类的相关方法, 所以我们在看到一些开源框架的时候会有对桥方法的判断==

静态上下文

在静态方法或静态字段中不能使用类的泛型类型参数。

例如下面这种是不被允许的

public class AA <T> {
    public static void aa(T t) {
        System.out.println(t);
    }
}

常见的泛型

public class GenericDemo {

    interface InterfaceClass<L> {
    }

    class SupperClass<M, N> {
    }

    /**
     * <T> 类型变量参数
     * SupperClass<T, String> 父类泛型
     * InterfaceClass<T> 接口泛型
     */
    class InnerClass<T> extends SupperClass<T, String> implements InterfaceClass<T> {

        /**
         * T: 类型变量泛型 => TypeVariable
         */
        private T ta;

        /**
         * <?>: 无界通配符泛型(也是参数化泛型) => WildcardType
         */
        private List<?> wildcardList;

        /**
         * <? extends Number, ? super Integer> : 上下界配符泛型(也是参数化泛型) => WildcardType
         */
        private Map<? extends Number, ? super Integer> boundedWildcardMap;

        /**
         * List<String>: 参数化泛型 => ParameterizedType
         */
        private List<String> parameterizedList;

        /**
         * 数组泛型 => GenericArrayType
         */
        private List<? extends Number>[] arrayWildcardList;

        /**
         * 数组泛型 => GenericArrayType
         */
        private List<String>[][] twoDimensionalArray;

        /**
         * <U, E extends RuntimeException>: U,E(方法类型参数)
         * @param param1 : 方法参数 List<T>: 参数化泛型 T:类型变量泛型
         * @param param2 : 方法参数 U: 方法类型参数
         * @param <U>   方法类型参数
         * @param <E>   方法类型参数
         */
        public <U, E extends RuntimeException> U exampleMethod(List<T> param1, U param2) throws E {
            return param2;
        }
    }
}

泛型类型

在这里插入图片描述

Type

public interface Type {
    default String getTypeName() {
        return toString();
    }
}

type接口就是一个标识接口, 仅有一个default的toString方法

TypeVariable

类型变量泛型

格式: public interface ClassName<D>, <R> R getR(), List<T> 其中的D,R,T就是类型变量

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    /**
     * 获取类型变量的上界
     */
    Type[] getBounds();

    /**
     * 获取该类型变量的声明的位置
     */
    D getGenericDeclaration();

    /**
     * 获取泛型变量的名称
     */
    String getName();

    /**
     * 获取类型变量的带注解的边界
     */
     AnnotatedType[] getAnnotatedBounds();
}

类型变量举例

  1. public class TypeVariableExample<T extends Number> 类上的泛型T
  2. private T field; 属性的类型T
  3. public <T> void method(T t, U u); 方法上的类型变量, T,U
  4. private List<T> list method(List<T> list) 属性或者方法中的T

下面用几个小例子说明熟悉一下相关api

/**
 * 类型变量测试(全)
 */
// 1.类型变量
public class TypeVariableExamples<T extends Number> {

    // 2. 泛型属性
    private T field;

    // 3. 泛型集合
    private List<T> list;

    // 4. 泛型方法(类型参数不同于类的泛型)
    public <U extends Integer, R, E extends RuntimeException> R method(T t, U u, R r) throws E {
        return r;
    }

    // 5. 泛型数组
    public T[] createArray() {
        return (T[]) new Object[10]; // 泛型数组创建时需要强制类型转换
    }
    // 6. 静态泛型方法
    public static <K, V> Map<K, V> createMap(K key, V value) {
        return Map.of(key, value);
    }
}

获取类上定义的泛型, TypeVariableExamples<T extends Number> => T extends Number

@Test
void classTypeVariableTest() {
    Class<TypeVariableExamples> genericExamplesClass = TypeVariableExamples.class;
    // 获取类上定义的泛型
    TypeVariable<Class<TypeVariableExamples>>[] typeParameters = genericExamplesClass.getTypeParameters();
    for (TypeVariable<Class<TypeVariableExamples>> typeParameter : typeParameters) {
        System.out.println(typeParameter.getTypeName());
        Type[] bounds = typeParameter.getBounds();
        for (Type bound : bounds) {
            System.out.println("上边界:" + bound);
        }
    }
}

结果

T
上边界:class java.lang.Number

获取字段上的类型泛型定义 private T field;

/**
 * 类型变量泛型
 */
@Test
void fieldTypeVariableTest() throws Exception {
    Class<TypeVariableExamples> genericExamplesClass = TypeVariableExamples.class;

    Field tempField = genericExamplesClass.getDeclaredField("field");
    Type genericType = tempField.getGenericType();
    System.out.println("字段是类型变量泛型吗:" + (genericType instanceof TypeVariable<?>));
    System.out.println("类型变量泛型:" + genericType.getTypeName());
}

结果

字段是类型变量泛型吗:true
类型变量泛型:T

泛型集合中的泛型变量private List<T> list;

/**
 * 参数变量泛型
 */
@Test
void parameterizedTypeTypeVariableTest() throws Exception {
    Class<TypeVariableExamples> genericExamplesClass = TypeVariableExamples.class;

    Field listField = genericExamplesClass.getDeclaredField("list");
    // 获取字段的泛型类型
    Type listFieldGenericType = listField.getGenericType();
    System.out.println("list字段是参数类泛型:" + (listFieldGenericType instanceof ParameterizedType));  // true
    ParameterizedType parameterizedType = (ParameterizedType) listFieldGenericType;
    // 原始类型(去掉泛型之后的类型)
    Type rawType = parameterizedType.getRawType();// list
    System.out.println("list的原始类型是Class吗:" + (rawType instanceof Class<?>));    // true
    System.out.println("list的原始类型是:" + rawType.getTypeName());    // java.util.List
    
    // 获取参数变量泛型的实际类型(集合中元素的实际类型)
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    for (Type actualTypeArgument : actualTypeArguments) {
        System.out.println(actualTypeArgument instanceof TypeVariable); // true
        System.out.println("参数变量是类型变量吗:" + (actualTypeArgument instanceof TypeVariable) + ";类型变量名称:" +actualTypeArgument.getTypeName());
    }
}

结果

list字段是参数类泛型:true
list的原始类型是Class:true
list的原始类型是:java.util.List
参数变量是类型变量吗:true;类型变量名称:T

泛型方法

public class TypeVariableExamples<T extends Number> {
    public <U extends Integer, R, E extends RuntimeException> R method(T t, U u, R r) throws E {
        return r;
    }
}

测试

/**
 * 方法上的类型变量测试
 */
@Test
void methodTypeVariableTest() throws Exception {
    Class<TypeVariableExamples> genericExamplesClass = TypeVariableExamples.class;
	// 泛型擦除导致这里Number和Integer类型要写具体的
    Method genericMethod = genericExamplesClass.getDeclaredMethod("method", Number.class, Integer.class, Object.class);
    TypeVariable<Method>[] methodTypeParameters = genericMethod.getTypeParameters();
    for (TypeVariable<Method> methodTypeParameter : methodTypeParameters) {
        System.out.println("方法的类型参数:" + methodTypeParameter.getTypeName());
    }
	// 获取方法泛型参数
    Type[] genericParameterTypes = genericMethod.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        if (genericParameterType instanceof TypeVariable<?> tv) {
            System.out.println("参数的泛型类型:" + tv.getTypeName());
            Type[] bounds = tv.getBounds();
            // 没有边界的返回java.lang.Object
            for (Type bound : bounds) {
                System.out.println("边界类型:" + bound.getTypeName() + ":是普通类吗:"+ (bound instanceof Class<?>) );
            }
        }
    }
    // 泛型返回值
    Type genericReturnType = genericMethod.getGenericReturnType();
    if (genericReturnType instanceof TypeVariable<?> tv) {
        System.out.println(tv.getTypeName());
    }

    Type[] genericExceptionTypes = genericMethod.getGenericExceptionTypes();
    for (Type genericExceptionType : genericExceptionTypes) {
        if (genericExceptionType instanceof TypeVariable<?> tv) {
            System.out.println("异常的泛型类型:" + tv.getTypeName());
        }
    }
}

注意

  1. 这里genericExamplesClass.getDeclaredMethod("method", Number.class, Integer.class, Object.class);这里由于T,U是指定了类型上界,在擦除的时候会替换为具体的值(Number,Integer), 所有要写具体的参数类型, R由于擦除会变成Object,所以是Object.class
  2. 方法上使用getTypeParameters方法获取的是方法泛型参数, 与类上面的不同public class TypeVariableExamples<T extends Number>类上面的是类泛型参数

结果

方法的类型参数:U
方法的类型参数:R
方法的类型参数:E

参数的泛型类型:T
边界类型:java.lang.Number:是普通类吗:true
参数的泛型类型:U
边界类型:java.lang.Integer:是普通类吗:true
参数的泛型类型:R
边界类型:java.lang.Object:是普通类吗:true

方法返回值的类型变量名:R

异常的泛型类型:E

泛型数组

public T[] createArray() {
    return (T[]) new Object[10]; // 泛型数组创建时需要强制类型转换
}

测试

@Test
void arrayTypeVariableTest() throws Exception {
    Class<TypeVariableExamples> genericExamplesClass = TypeVariableExamples.class;

    Method createArrayMethod = genericExamplesClass.getDeclaredMethod("createArray");
    // 泛型返回值
    Type arrGenericReturnType = createArrayMethod.getGenericReturnType();
    // 判断泛型数组
    if (arrGenericReturnType instanceof GenericArrayType genericArrayType) {
        // 获取数组元素的泛型类型
        Type genericComponentType = genericArrayType.getGenericComponentType();
        System.out.println("数组类型:" + genericComponentType.getTypeName() + ":是类型泛型吗:"+ (genericComponentType instanceof TypeVariable<?>) );
    }
}

结果

数组类型:T:是类型泛型吗:true

静态泛型方法

public static <K, V> Map<K, V> createMap(K key, V value) {
    return Map.of(key, value);
}

测试

@Test
void staticMethodTest() throws Exception {

    Method createMapMethod = TypeVariableExamples.class.getDeclaredMethod("createMap", Object.class, Object.class);
	// 方法的类型变量
    TypeVariable<Method>[] typeParameters = createMapMethod.getTypeParameters();
    for (TypeVariable<Method> typeParameter : typeParameters) {
        System.out.println("静态泛型方法类型变量:" + typeParameter.getTypeName());
    }

    // 参数的泛型类型
    Type[] createMapParameterTypes = createMapMethod.getGenericParameterTypes();
    for (Type createMapParameterType : createMapParameterTypes) {
        if (createMapParameterType instanceof TypeVariable<?> tv) {
            System.out.println("静态泛型方法参数泛型类型:" + tv.getTypeName());
        }
    }
    // 方法的泛型返回值
    Type createMapReturnType = createMapMethod.getGenericReturnType();
    if (createMapReturnType instanceof ParameterizedType pt) {
        Type[] atas = pt.getActualTypeArguments();
        for (Type ata : atas) {
            System.out.println("参数变量类型:" + ata.getTypeName() + ":是类型泛型吗:"+ (ata instanceof TypeVariable<?>) );
        }
    }
}

ParameterizedType

ParameterizedType 是表示参数化泛型的接口,用于描述诸如 List 这样的泛型类型。

public interface ParameterizedType extends Type {
    /**
     * 获取该参数化类型的实际类型参数。
     */
    Type[] getActualTypeArguments();
    
    /**
     * 返回参数化类型的原始类型,即去掉泛型信息后的基础类或接口。
     */
    Type getRawType();
    
    /**
     * 获取参数化类型的拥有者类型(owner type)。这是针对内部类定义的。如果参数化类型是某个内部类的类型,并且这个内部类定义在某个外部类中,getOwnerType() 将返回外部类的 Type。如果类型不是内部类,getOwnerType() 返回 null。
     */
    Type getOwnerType();
}

常见的参数化泛型如下

List<String>
List<T>
List<?>
Map<? extends Number, ? super Integer>

api举例

/**
 * 参数类泛型测试
 */
public class ParameterizedTypeTest<T> {

    private List<String> list1;
    private List<T> list2;

    private List<?> list3;

    private Map<? extends Number, ? super Integer> map;


    private GetOwnerTypeTest.NestedClass<String, String> nestedClass;

    class NestedClass<K, V> {

    }

    public <U> Map<U, ?> exampleMethod(List<T> t) {
        return null;
    }
}

以下测试均放在ParameterizedTypeTest类中进行

原始类型的泛型参数

private List<String> list1;

/**
 * 原始类型的泛型参数
 */
@Test
void classParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Field list1Field = clazz.getDeclaredField("list1");
    Type genericType = list1Field.getGenericType();
    System.out.println("list1是泛型参数吗:" + (genericType instanceof ParameterizedType) + ";泛型名:" + genericType.getTypeName());
    System.out.println("list1泛型参数的原始类型:" + ((ParameterizedType)genericType).getRawType().getTypeName());
    if (genericType instanceof ParameterizedType pt) {
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type at : actualTypeArguments) {
            System.out.println("参数泛型是原始类型吗:" + (at instanceof Class<?>) + ";类型名:" + at.getTypeName());
        }
    }
}

结果

list1是泛型参数吗:true;泛型名:java.util.List<java.lang.String>
list1泛型参数的原始类型:java.util.List
参数泛型是原始类型吗:true;类型名:java.lang.String

类型变量的泛型参数

private List<T> list2;

/**
 * 类型变量的泛型参数
 */
@Test
void typeVariableParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Field list2Field = clazz.getDeclaredField("list2");
    Type genericType = list2Field.getGenericType();
    System.out.println("list1是参数泛型吗:" + (genericType instanceof ParameterizedType) + ";泛型名:" + genericType.getTypeName());
    System.out.println("list2泛型参数的原始类型:" + ((ParameterizedType)genericType).getRawType().getTypeName());
    if (genericType instanceof ParameterizedType pt) {
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type at : actualTypeArguments) {
            System.out.println("参数泛型是类型变量吗:" + (at instanceof TypeVariable<?>) + ";类型名:" + at.getTypeName());
        }
    }
}

结果

list1是参数泛型吗:true;泛型名:java.util.List<T>
list2泛型参数的原始类型:java.util.List
参数泛型是类型变量吗:true;类型名:T

通配符泛型参数

private List<?> list3;

/**
 * 通配符泛型参数
 */
@Test
void wildcardParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Field list3Field = clazz.getDeclaredField("list3");
    Type genericType = list3Field.getGenericType();
    System.out.println("list1是参数泛型吗:" + (genericType instanceof ParameterizedType) + ";泛型名:" + genericType.getTypeName());
    System.out.println("list3泛型参数的原始类型:" + ((ParameterizedType)genericType).getRawType().getTypeName());
    if (genericType instanceof ParameterizedType pt) {
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type at : actualTypeArguments) {
            System.out.println("参数泛型是类型变量吗:" + (at instanceof WildcardType) + ";类型名:" + at.getTypeName());
        }
    }
}

结果

list1是参数泛型吗:true;泛型名:java.util.List<?>
list3泛型参数的原始类型:java.util.List
参数泛型是类型变量吗:true;类型名:?

private Map<? extends Number, ? super Integer> map;

@Test
void wildcardBoundsParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Field list1Field = clazz.getDeclaredField("map");
    Type genericType = list1Field.getGenericType();
    System.out.println("map是参数泛型吗:" + (genericType instanceof ParameterizedType) + ";泛型名:" + genericType.getTypeName());
    System.out.println("map泛型参数的原始类型:" + ((ParameterizedType)genericType).getRawType().getTypeName());
    if (genericType instanceof ParameterizedType pt) {
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type at : actualTypeArguments) {
            System.out.println("参数泛型是类型变量吗:" + (at instanceof WildcardType) + ";类型名:" + at.getTypeName());
        }
    }
}

结果

map是参数泛型吗:true;泛型名:java.util.Map<? extends java.lang.Number, ? super java.lang.Integer>
map泛型参数的原始类型:java.util.Map
参数泛型是类型变量吗:true;类型名:? extends java.lang.Number
参数泛型是类型变量吗:true;类型名:? super java.lang.Integer

方法上的泛型参数

public <U> Map<U, ?> exampleMethod(List<T> t) {
    return null;
}

测试

@Test
void methodParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Method method = clazz.getDeclaredMethod("exampleMethod", List.class);
    // 方法类型变量集合
    TypeVariable<Method>[] typeParameters = method.getTypeParameters();
    for (TypeVariable<Method> typeParameter : typeParameters) {
        System.out.println("方法的类型参数:" + typeParameter.getTypeName());
    }
    // 方法泛型参数
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        if (genericParameterType instanceof ParameterizedType pt) {
            System.out.println("exampleMethod的参数泛型名:" + pt.getTypeName() + ";原始类型:" + pt.getRawType());
            Type[] actualTypeArguments = pt.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("参数泛型是类型变量吗:" + (actualTypeArgument instanceof TypeVariable<?>) + ";类型名:" + actualTypeArgument.getTypeName());
            }
        }
    }
    // 方法泛型返回值
    Type genericReturnType = method.getGenericReturnType();
    if (genericReturnType instanceof ParameterizedType pt) {
        System.out.println("exampleMethod的返回值泛型名:" + pt.getTypeName() + ";原始类型:" + pt.getRawType());
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println("参数泛型是类型变量吗:" + (actualTypeArgument instanceof TypeVariable<?>) + ";类型名:" + actualTypeArgument.getTypeName());
        }
    }
}

结果

方法的类型参数:U
exampleMethod的参数泛型名:java.util.List<T>;原始类型:interface java.util.List
参数泛型是类型变量吗:true;类型名:T
exampleMethod的返回值泛型名:java.util.Map<U, ?>;原始类型:interface java.util.Map
参数泛型是类型变量吗:true;类型名:U
参数泛型是类型变量吗:false;类型名:?

内部类(参数化类型的拥有者类型)

private GetOwnerTypeTest.NestedClass<String, String> nestedClass;
class NestedClass<K, V> {
}

测试

@Test
void nestedClassParameterizedTypeTest() throws Exception {
    Class<ParameterizedTypeTest> clazz = ParameterizedTypeTest.class;
    Field nestedClassField = clazz.getDeclaredField("nestedClass");
    Type genericType = nestedClassField.getGenericType();
    System.out.println("nestedClass是参数泛型吗:" + (genericType instanceof ParameterizedType) + ";泛型名:" + genericType.getTypeName());
    System.out.println("nestedClass泛型参数的原始类型:" + ((ParameterizedType)genericType).getRawType().getTypeName());
    if (genericType instanceof ParameterizedType pt) {
        Type ownerType = pt.getOwnerType();
        System.out.println("nestedClass的owner类型:" + ownerType.getTypeName());
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type at : actualTypeArguments) {
            System.out.println("参数泛型是原始类型吗:" + (at instanceof Class<?>) + ";类型名:" + at.getTypeName());
        }
    }
}

结果

nestedClass是参数泛型吗:true;泛型名:per.qiao.myutils.generic.parameterizedype.GetOwnerTypeTest$NestedClass<java.lang.String, java.lang.String>
nestedClass泛型参数的原始类型:per.qiao.myutils.generic.parameterizedype.GetOwnerTypeTest$NestedClass
nestedClass的owner类型:per.qiao.myutils.generic.parameterizedype.GetOwnerTypeTest
参数泛型是原始类型吗:true;类型名:java.lang.String
参数泛型是原始类型吗:true;类型名:java.lang.String

WildcardType

通配符类型的泛型; 它不能单独使用, 只能出现在参数泛型中, 作为一个泛型类型来用

public interface WildcardType extends Type {
    
    /**
     * 获取通配符类型的上边界(Upper Bound)
     */
    Type[] getUpperBounds();
    
    /**
     * 获取通配符类型的下边界(Upper Bound)
     */
    Type[] getLowerBounds();
}

常见的占位符泛型有 List<?> list,Map<? extends Number, ? super Integer> map List<?>[] wildcardArray

api测试

先写一个通配符泛型的解析方法, 大家不要纠结这个代码写的怎么样, 能说明问题就行

private void expressWildcard(Type genericType) {
    System.out.println("泛型类型:" + genericType.getTypeName());

    if (genericType instanceof ParameterizedType pt) {
        System.out.println("参数泛型的原始类型:" + pt.getRawType());
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type ata : actualTypeArguments) {
            System.out.println("参数泛型的元素类型:" + ata.getTypeName());
            if (ata instanceof WildcardType wt) {
                Type[] upperBounds = wt.getUpperBounds();
                for (Type upperBound : upperBounds) {
                    System.out.println("通配符参数类型的上边界: " + upperBound.getTypeName());
                }
                Type[] lowerBounds = wt.getLowerBounds();
                for (Type lowerBound : lowerBounds) {
                    System.out.println("通配符参数类型的下边界: " + lowerBound.getTypeName());
                }
            }
        }
    }
}

常规通配符private List<?> list;

@Test
void normalWildcardTest() throws Exception {
    Class<WildcardTypeTest> wildcardTypeTestClass = WildcardTypeTest.class;
    Field listField = wildcardTypeTestClass.getDeclaredField("list");
    // 字段的泛型类型
    Type genericType = listField.getGenericType();
    System.out.println("泛型类型:" + genericType.getTypeName());

    expressWildcard(genericType);
}

结果

泛型类型:java.util.List<?>
参数泛型的原始类型:interface java.util.List
参数泛型的元素类型:?
通配符参数类型的上边界: java.lang.Object

上下边界的通配符泛型Map<? extends Number, ? super Integer> map

@Test
void boundsWildcardTest() throws Exception {
    Class<WildcardTypeTest> wildcardTypeTestClass = WildcardTypeTest.class;
    Field listField = wildcardTypeTestClass.getDeclaredField("map");
    // 字段的泛型类型
    Type genericType = listField.getGenericType();
    this.expressWildcard(genericType);
}

结果

泛型类型:java.util.Map<? extends java.lang.Number, ? super java.lang.Integer>
参数泛型的原始类型:interface java.util.Map
参数泛型的元素类型:? extends java.lang.Number
通配符参数类型的上边界: java.lang.Number

参数泛型的元素类型:? super java.lang.Integer
通配符参数类型的上边界: java.lang.Object
通配符参数类型的下边界: java.lang.Integer

数组通配符泛型List<?>[] wildcardArray

@Test
void arrayWildcardTest() throws Exception {
    Class<WildcardTypeTest> wildcardTypeTestClass = WildcardTypeTest.class;
    Field listField = wildcardTypeTestClass.getDeclaredField("wildcardArray");
    // 字段的泛型类型
    Type genericType = listField.getGenericType();
    System.out.println("泛型类型:" + genericType.getTypeName());
    if (genericType instanceof GenericArrayType gat) {
        // 获取数组类型
        Type genericComponentType = gat.getGenericComponentType();
        if (genericComponentType instanceof ParameterizedType pt) {
            expressWildcard(pt);
        }
    }
}

结果

泛型类型:java.util.List<?>[]
泛型类型:java.util.List<?>
参数泛型的原始类型:interface java.util.List
参数泛型的元素类型:?
通配符参数类型的上边界: java.lang.Object

方法中的通配符泛型

public void complexWildcard(List<? extends Number> list1, List<? super Integer> list2) {
}

测试

@Test
void wildcardTypeTest() throws Exception {

    Class<WildcardTypeTest> wildcardTypeTestClass = WildcardTypeTest.class;
    Method complexWildcardMethod = wildcardTypeTestClass.getDeclaredMethod("complexWildcard", List.class, List.class);
    Type[] genericParameterTypes = complexWildcardMethod.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        if (genericParameterType instanceof ParameterizedType pt) {
            expressWildcard(pt);
        }
    }
}

结果

泛型类型:java.util.List<? extends java.lang.Number>
参数泛型的原始类型:interface java.util.List
参数泛型的元素类型:? extends java.lang.Number
通配符参数类型的上边界: java.lang.Number
泛型类型:java.util.List<? super java.lang.Integer>

参数泛型的原始类型:interface java.util.List
参数泛型的元素类型:? super java.lang.Integer
通配符参数类型的上边界: java.lang.Object
通配符参数类型的下边界: java.lang.Integer

GenericArrayType

GenericArrayType 是一个表示泛型数组类型的接口。用于描述数组类型中的元素具有泛型的情况。

public interface GenericArrayType extends Type {
    
    /**
     * 获取数组的元素类型
     */
    Type getGenericComponentType();
}

一般有如下形式T[] genericArray List<? extends Number>[] wildcardArray以及二维数组List<String>[][] twoDimensionalArray

先写个工具方法(非通用的,仅在此演示用),不要拘泥于代码写的怎么样

public class GenericComponentTypeExample<T> {
    
    private T[] genericArray;
    
    private List<? extends Number>[] wildcardArray;

    private List<String>[][] twoDimensionalArray;
    
	private void expressGenericArrayType(Type genericType) {
        if (genericType instanceof GenericArrayType gat) {
            Type genericComponentType = gat.getGenericComponentType();
            System.out.println("通配符泛型数组元素类型:" + genericComponentType.getTypeName());
            // 参数泛型
            if (genericComponentType instanceof ParameterizedType pt) {
                System.out.println("通配符泛型数组元素原始类型:" + pt.getRawType().getTypeName());
                Type[] actualTypeArguments = pt.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    if (actualTypeArgument instanceof WildcardType wt) {
                        for (Type upperBound : wt.getUpperBounds()) {
                            System.out.println("通配符泛型数组元素类型变量上界:" + upperBound.getTypeName());
                        }
                        Type[] lowerBounds = wt.getLowerBounds();
                        for (Type lowerBound : lowerBounds) {
                            System.out.println("通配符泛型数组元素类型变量下界:" + lowerBound.getTypeName());
                        }
                    } else if (actualTypeArgument instanceof Class<?>) {
                        System.out.println("通配符泛型数组元素原始类型:" + actualTypeArgument.getTypeName());
                    }
                }
            } else if (genericComponentType instanceof GenericArrayType gt) {
                expressGenericArrayType(gt);
            }
        }
    }
}

类型变量数组测试

T[] genericArray

/**
 * 类型变量数组测试
 */
@Test
void typeVariableArrayTest() throws Exception {
    Class<GenericComponentTypeExample> clazz = GenericComponentTypeExample.class;
    Field genericArrayField = clazz.getDeclaredField("genericArray");
    // 字段的泛型类型
    Type genericType = genericArrayField.getGenericType();
    System.out.println("类型变量泛型数组:" + genericType.getTypeName());
    if (genericType instanceof GenericArrayType gat) {
        Type genericComponentType = gat.getGenericComponentType();
        System.out.println("数组类型:" + genericComponentType.getTypeName() + ":是类型泛型吗:"+ (genericComponentType instanceof TypeVariable<?>) );
    }
}

结果

类型变量泛型数组:T[]
数组类型:T:是类型泛型吗:true

通配符泛型数组

List<? extends Number>[] wildcardArray

@Test
void wildcardArrayTest() throws Exception {
    Class<GenericComponentTypeExample> clazz = GenericComponentTypeExample.class;
    Field wildcardArrayField = clazz.getDeclaredField("wildcardArray");
    // 字段的泛型类型
    Type genericType = wildcardArrayField.getGenericType();
    this.expressGenericArrayType(genericType);
}

结果

通配符泛型数组元素类型:java.util.List<? extends java.lang.Number>
通配符泛型数组元素原始类型:java.util.List
通配符泛型数组元素类型变量上界:java.lang.Number

二维泛型数组

List<String>[][] twoDimensionalArray

@Test
void twoDimensionalArrayTest() throws Exception {
    Class<GenericComponentTypeExample> clazz = GenericComponentTypeExample.class;
    Field twoDimensionalArrayField = clazz.getDeclaredField("twoDimensionalArray");
    // 字段的泛型类型
    Type genericType = twoDimensionalArrayField.getGenericType();
    System.out.println("二维泛型数组:" + genericType.getTypeName());
    this.expressGenericArrayType(genericType);
}

结果

二维泛型数组:java.util.List<java.lang.String>[][]
通配符泛型数组元素类型:java.util.List<java.lang.String>[]
通配符泛型数组元素类型:java.util.List<java.lang.String>
通配符泛型数组元素原始类型:java.util.List
通配符泛型数组元素原始类型:java.lang.String

Class

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement,
                              TypeDescriptor.OfField<Class<?>>,
                              Constable {
    /**
     * 获取类上定义的泛型
     */
    public TypeVariable<Class<T>>[] getTypeParameters() {
        ClassRepository info = getGenericInfo();
        if (info != null)
            return (TypeVariable<Class<T>>[])info.getTypeParameters();
        else
            return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
    }

    /**
     * 获取直接父类, 包含泛型
     */
	public Type getGenericSuperclass() {
        ClassRepository info = getGenericInfo();
        if (info == null) {
            return getSuperclass();
        }

        // Historical irregularity:
        // Generic signature marks interfaces with superclass = Object
        // but this API returns null for interfaces
        if (isInterface()) {
            return null;
        }

        return info.getSuperclass();
    }
   
    /**
     * 获取直接接口, 包括泛型
     */
    public Type[] getGenericInterfaces() {
        ClassRepository info = getGenericInfo();
        return (info == null) ?  getInterfaces() : info.getSuperInterfaces();
    }
                                  
    /**
     * 获取数组元素类型
     */
    public Class<?> getComponentType() {
        // Only return for array types. Storage may be reused for Class for instance types.
        if (isArray()) {
            return componentType;
        } else {
            return null;
        }
    }
}

类上的泛型一般叫做类型变量; 例如 public class Level1Class<T> extends Level0Class<List<T>> implements InterfaceClass<List<T>>

测试

/**
 * 泛型类
 */
public class ClassGenericTest {

    class B<E, F> implements C<E, F, Boolean> {
    }

    interface C<L, M, N> {
    }

    class A<T> extends B<T, String> implements C<T, String, Boolean> {
    }
}

获取类泛型参数

说白点就是类上定义的泛型变量, 例如 class A<T,U>中的T、U

@Test
void getTypeParametersTest() {
    TypeVariable<Class<A>>[] typeParameters = A.class.getTypeParameters();
    for (TypeVariable<Class<A>> tv : typeParameters) {
        System.out.println(tv.getName());
    }
}

结果

T

获取直接泛型父类

如果继承的父类有泛型信息,那么会直接获取该泛型信息, 例如class A<T> extends B<T, String>中的B<T, String>就是一个参数泛型ParameterizedType

@Test
void getGenericSuperclassTest() {
    Type genericSuperclass = A.class.getGenericSuperclass();
    System.out.println("直接父类的泛型对象:" + genericSuperclass.getTypeName());
    if (genericSuperclass instanceof ParameterizedType pt) {
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println("参数泛型的类型:" + actualTypeArgument.getTypeName());
        }
    }
}

结果

直接父类的泛型对象:per.qiao.myutils.clazz.ClassGenericTest$B<T, java.lang.String>
参数泛型的类型:T
参数泛型的类型:java.lang.String

获取直接泛型接口

如果继承的接口有泛型信息,那么会直接获取该泛型信息, 例如class A<T> implements C<T, String, Boolean>中的C<T, String, Boolean>就是一个参数泛型ParameterizedType

@Test
void getGenericInterfacesTest() {
    Type[] genericInterfaces = A.class.getGenericInterfaces();
    for (Type genericInterface : genericInterfaces) {
        System.out.println("直接接口的泛型对象:" + genericInterface.getTypeName());
        if (genericInterface instanceof ParameterizedType pt) {
            Type[] actualTypeArguments = pt.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("参数泛型的类型:" + actualTypeArgument.getTypeName());
            }
        }
    }
}

结果

直接接口的泛型对象:per.qiao.myutils.clazz.ClassGenericTest$C<T, java.lang.String, java.lang.Boolean>
参数泛型的类型:T
参数泛型的类型:java.lang.String
参数泛型的类型:java.lang.Boolean

获取数组类型的元素类型

@Test
void getComponentTypeTest() {
    int[] arr1 = {1, 2, 3};
    Class<? extends int[]> aClass = arr1.getClass();
    System.out.println(aClass);     // class [I
    System.out.println("是数组吗:" + aClass.isArray());   // true
    System.out.println("数组的元素类型:" + aClass.getComponentType().getTypeName());  // int

    int[][] arr2 = {{1, 2}, {3, 4}};
    Class<? extends int[][]> aClass1 = arr2.getClass(); // class [[I
    System.out.println(aClass1);
    System.out.println("是数组吗:" + aClass1.isArray());  // true
    System.out.println("外层数组的元素类型" + aClass1.getComponentType().getTypeName()); // int[]

    Class<?> componentType = aClass1.getComponentType();
    System.out.println("内嵌对象是数组吗:" + componentType.isArray());  // true
    Class<?> componentType1 = componentType.getComponentType();
    System.out.println("内嵌二维数组的元素类型:" + componentType1.getTypeName());  // int
}

泛型与注解的碰撞

在java1.8后, 注解也可以声明在泛型上了, 用于指定当前泛型参数参数必须有该注解标识

for demo

public class AnnotationGenericTest {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface MyAnnotation {
    }
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface ExAnnotation {
    }

    public class AnnotatedTypeExample<T extends @MyAnnotation Number> {
        private T annotatedField;

        public <E extends @ExAnnotation RuntimeException, @MyAnnotation R> @MyAnnotation R getAnnotatedField(@MyAnnotation T t) throws @ExAnnotation E {
            return null;
        }
    }
}

类泛型参数上的注解

@Test
void typeParameterAnnotationTest() {
    Class<AnnotatedTypeExample> clazz = AnnotatedTypeExample.class;
    TypeVariable<Class<AnnotatedTypeExample>>[] typeParameters = clazz.getTypeParameters();
    for (TypeVariable<Class<AnnotatedTypeExample>> tv : typeParameters) {
        printAnnotations(tv);
    }
}

结果

方法参数泛型名称:T
注解类型:class java.lang.Number;Class类型吗:true
泛型上的注解:@per.qiao.myutils.generic.genericannotation.AnnotationGenericTest$MyAnnotation()

方法上的相关注解

@Test
void methodParameterAnnotationTest() throws Exception {
    System.out.println("===========方法类型参数===============");
    Class<AnnotatedTypeExample> clazz = AnnotatedTypeExample.class;
    Method method = clazz.getDeclaredMethod("getAnnotatedField", Number.class);
    TypeVariable<Method>[] typeParameters = method.getTypeParameters();
    for (TypeVariable<Method> tv : typeParameters) {
        printAnnotations(tv);
    }
    System.out.println("============方法参数类型==============");
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    for (Type type : genericParameterTypes) {
        System.out.println("参数类型:" + type.getTypeName());
        if (type instanceof TypeVariable<?> tv) {
            printAnnotations(tv);
        }
    }
    System.out.println("============方法返回值类型==============");
    Type genericReturnType = method.getGenericReturnType();
    System.out.println("方法返回值泛型类型:" + genericReturnType.getTypeName());
    if (genericReturnType instanceof TypeVariable<?> tv) {
        printAnnotations(tv);
    }
    System.out.println("============方法抛出异常类型==============");
    Type[] genericExceptionTypes = method.getGenericExceptionTypes();
    for (Type genericExceptionType : genericExceptionTypes) {
        if (genericExceptionType instanceof TypeVariable<?> tv) {
            printAnnotations(tv);
        }
    }
}

private void printAnnotations(TypeVariable<?> tv) {
    System.out.println("方法参数泛型名称:" + tv.getTypeName());
    AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();
    for (AnnotatedType annotatedBound : annotatedBounds) {
        System.out.println("注解类型:" + annotatedBound.getType() + "; 是Class类型吗:" + (annotatedBound.getType() instanceof Class<?>));
        Annotation[] annotations = annotatedBound.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("泛型上的注解:" + annotation.toString());
        }
    }
}

结果

===========方法类型参数===============
方法参数泛型名称:E
注解类型:class java.lang.RuntimeException;Class类型吗:true
泛型上的注解:@per.qiao.myutils.generic.genericannotation.AnnotationGenericTest$ExAnnotation()
方法参数泛型名称:R
注解类型:class java.lang.Object;Class类型吗:true
============方法参数类型==============
参数类型:T
方法参数泛型名称:T
注解类型:class java.lang.Number;Class类型吗:true
泛型上的注解:@per.qiao.myutils.generic.genericannotation.AnnotationGenericTest$MyAnnotation()
============方法返回值类型==============
方法返回值泛型类型:R
方法参数泛型名称:R
注解类型:class java.lang.Object;Class类型吗:true
============方法抛出异常类型==============
方法参数泛型名称:E
注解类型:class java.lang.RuntimeException;Class类型吗:true
泛型上的注解:@per.qiao.myutils.generic.genericannotation.AnnotationGenericTest$ExAnnotation()

工具类推荐

spring有关泛型的工具类

GenericTypeResolver

mybatis有关泛型的工具类

TypeParameterResolver

遗留的问题

指定方法泛型类型

package per.qiao.myutils.generic.genericerase;

import java.util.function.Consumer;

public class GenericExample {

    static class A<T> {
        public <R> A<T> doSomething(Consumer<R> func) {
            return this;
        }

        public A<T> doSomething2(Consumer<T> func) {
            return this;
        }

        public void say() {
        }

    }

    static class B {
        public <R> B doSomething(Consumer<R> func) {
            return this;
        }

        public void say() {
        }
    }

    public static <T> A<T> getA() {
        return new A<>();
    }

    public static B getB() {
        return new B();
    }


    public static void main(String[] args) {
        GenericExample.getA().<A<String>>doSomething(A::say);
        GenericExample.getB().doSomething(B::say);
    }
}

这里GenericExample.getA().<A<String>>doSomething(A::say);需要用<A<String>>指定A类中doSomething的方法变量R的类型, 但是B类的doSomething不需要; 为什么呢? 目前我也不知道。。。

个人公众号
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

uncleqiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值