介绍
泛型是java1.5引入的新特性, 泛型的引入主要是为了提高 Java 编程语言的类型安全性和代码重用性,具体意义包括:
- 类型安全:
• 泛型在编译时提供了类型检查,确保在使用集合或其他数据结构时,传入的类型是正确的。这可以有效减少运行时类型转换错误,提高代码的安全性。
- 消除强制类型转换:
• 使用泛型可以避免在从集合中取出元素时需要进行强制类型转换。例如,使用 List<String> 时,取出元素不需要强制转换为 String 类型,直接使用即可。这使得代码更简洁、可读性更强。
- 增强代码的可重用性:
• 泛型允许开发者编写与类型无关的代码,从而实现更高的代码重用性。一个使用泛型的类或方法可以适用于多种数据类型,而无需为每种数据类型编写重复的代码。
- 提升可维护性:
• 由于类型安全和简化的代码结构,使用泛型的代码更容易理解和维护。当出现问题时,编译器可以提供更好的错误信息,使得调试和修复变得更加简单。
注意事项
类型擦除
例如
@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> intInstance
和Demo1<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();
}
类型变量举例
public class TypeVariableExample<T extends Number>
类上的泛型Tprivate T field;
属性的类型Tpublic <T> void method(T t, U u)
; 方法上的类型变量, T,Uprivate 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());
}
}
}
注意
- 这里
genericExamplesClass.getDeclaredMethod("method", Number.class, Integer.class, Object.class);
这里由于T,U是指定了类型上界,在擦除的时候会替换为具体的值(Number,Integer), 所有要写具体的参数类型, R由于擦除会变成Object,所以是Object.class - 方法上使用
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不需要; 为什么呢? 目前我也不知道。。。
个人公众号