在java中,泛型算是必须要掌握的一块硬核知识,在很多地方都会用到,这块如果理解了,在阅读其他框架源码的时候会让你更容易一些。
关于泛型的解析上面,我们需要先了解一些类和接口,这些比较关键,这些都位于java.lang.reflect包中,类图如下:
reflect包中的一些类 Type接口 这是一个顶层接口,java中的任何类型都可以用这个来表示,这个接口是Java编程语言中所有类型的公共超接口。这些类型包括原始类型、泛型类型、泛型变量类型、通配符类型、泛型数组类型、数组类型等各种类型。
这个接口代码比较简单,源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package java.lang.reflect;public interface Type { default String getTypeName () { return toString(); } }
getTypeName(),用于返回具体类型的名称,是一个默认方法,默认会调用当前类的toString方法,实现类也可以对这个方法重写。
GenericDeclaration接口 所有声明泛型变量的公共接口,这个接口中定义了一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package java.lang.reflect;public interface GenericDeclaration extends AnnotatedElement { public TypeVariable<?>[] getTypeParameters(); }
getTypeParameters(),这个方法用于获取声明的泛型变量类型清单。
泛型变量可以在类和方法中进行声明,从上面类图中也可以看出来,java中任何类可以使用Class对象表示,方法可以用Method类表示,类图中可以知,Class类和Method类实现了GenericDeclaration接口,所以可以调用他们的getTypeParameters方法获取其声明的泛型参数列表。
1 public class Demo1 <T1, T2 extends Integer , T3 extends Demo1I1 & Demo1I2>
上面代码表示Demo1这个类中声明了3个泛型变量类型:T1、T2、T3,所以如果去调用这个类的Clas对象中的getTypeParameters方法可以获取到这三个泛型变量的信息。
1 2 3 public <T1, T2 extends Integer , T3 extends Demo2I1 & Demo2I2> T3 m1 (T1 t1, T2 t2, T3 t3, String s) { return t3; }
上面m1方法中声明了三个泛型类型变量:T1、T2、T3;java中可以方法的任何信息都可以通过Method对象来获取,Mehod类实现了GenericDeclaration接口,所以Method类中实现了GenericDeclaration接口中的getTypeParameters方法,调用这个方法就可以获取m1方法中3个泛型变量类型的信息。
Class类 Class类的对象表示JVM中一个类或者接口,每个java对象被加载到jvm中都会表现为一个Class类型的对象,java中的数组也被映射为Class对象,所有元素类型相同且维数相同的数组都共享一个class对象,通过Class对象可以获取类或者接口中的任何信息,比如:类名、类中声明的泛型信息、类的修饰符、类的父类信息、类的接口信息、类中的任何方法信息、类中任何字段信息等等。
Class对象获取方式 在程序中我们可以通过3中方式获取Class对象:1 2 3 1. 类名.class2. 对象.getClass()3. Class.forName("类或者接口的完整名称" )
常用的方法:
Field[] getFields() 这个方法会返回当前类的以及其所有父类、父类的父类中所有public类型的字段。
Field[] getDeclaredFields() 这个方法会返回当前类中所有字段(和修饰符无关),也就说不管这个字段是public还是private或者是protected,都会返回,有一点需要注意,只返回自己内部定义的字段,不包含其父类中的,这点需要注意,和getFields是有区别的。
Method[] getMethods() 这个方法会返回当前类的以及其所有父类的、父类的父类的、自己实现的接口、父接口继承的接口中的所有public类型的方法,需要注意一下,接口中的方法默认都是public类型的,接口中的方法public修饰符是可以省略的。
Method[] getDeclaredMethods() 返回当前类中定义的所有方法,不管这个方法修饰符是什么类型的,注意只包含自己内部定义的方法,不包含当前类的父类或者其实现的接口中定义的。
Type getGenericSuperclass() 返回父类的类型信息,如果父类是泛型类型,会返回超类中泛型的详细信息,这个方法比较关键,后面会有详细案例。
TypeVariable<Class>[] getTypeParameters() Class类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Class类中实现了这个接口,用于返回当前类中声明的泛型变量参数列表。
Method类 这个类用来表示java中的任何一个方法,通过这个类可以获取java中方法的任何信息,比如:方法的修饰符、方法名称、方法的参数、方法返回值、方法中声明的泛型参数列表等方法的一切信息。
常用的方法
String getName() 用来获取方法的名称。
Type[] getGenericParameterTypes() 返回方法的参数信息,如果参数是泛型类型的,会返回泛型的详细信息,这个方法后面会演示。
Type getGenericReturnType() 返回方法的返回值类型,如果返回值是泛型的,会包含泛型的详细信息。
TypeVariable[] getTypeParameters() Method类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Method类中实现了这个接口,用于返回当前方法中声明的泛型变量参数列表。
Field类 这个类用来表示java中的字段,通过这个类可以获取java中字段的任何信息,比如:字段的修饰符、字段名称、字段类型、泛型字段的类型等字段的一切信息。
常用的方法
String getName() 获取字段的名称。
Class<?> getType() 获取字段类型所属的Class对象。
Type getGenericType() 获取字段的类型,如果字段是泛型类型的,会返回泛型类型的详细信息;如果字段不是泛型类型的,和getType返回的结果是一样的。
Class<?> getDeclaringClass() 获取这个字段是在哪个类中声明的,也就是当前字段所属的类。
ParameterizedType接口 这个接口表示参数化类型,例如List、Map<Integer,String>、UserMapper这种带有泛型的类型。
常用方法
Type[] getActualTypeArguments() 获取泛型类型中的类型列表,就是<>中包含的参数列表,如:List泛型类型列表只有一个是String,而Map<Integer,String>泛型类型中包含2个类型:Integer和String,UserMapper泛型类型为UserModel,实际上就是<和>中间包含的类型列表。
Type getRawType() 返回参数化类型中的原始类型,比如:List的原始类型为List,UserMapper原始类型为UserMapper,也就是<符号前面的部分。
Type[] getOwnerType()
1 返回当前类型所属的类型。例如存在A<T>类,其中定义了内部类InnerA<I>, 则InnerA<I>所属的类型为A<I>,如果是顶层类型则返回null。这种关系比较常见的示例是Map<K,V>接口与Map.Entry<K,V>接口,Map<K,V>接口是Map.Entry<K,V>接口的所有者。
TypeVariable接口 这个接口表示的是泛型变量,例如:List中的T就是类型变量;而class C1<T1,T2,T3>{}表示一个类,这个类中定义了3个泛型变量类型,分别是T1、T2和T2,泛型变量在java中使用TypeVariable接口来表示,可以通过这个接口提供的方法获取泛型变量类型的详细信息。
常用的方法
Type[] getBounds() 获取泛型变量类型的上边界,如果未明确什么上边界默认为Object。例如:class Test中K的上边界只有一个,是Person;而class Test<T extend List & Iterable>中T的上边界有2个,是List和Iterable
D getGenericDeclaration() 获取声明该泛型变量的原始类型,例如:class Test中的K为泛型变量,这个泛型变量时Test类定义的时候声明的,说明如果调用getGenericDeclaration方法返回的就是Test对应的Class对象。
还有方法中也可以定义泛型类型的变量,如果在方法中定义,那么上面这个方法返回的就是定义泛型变量的方法了,返回的就是Method对象。
String getName() 获取在源码中定义时的名字,如:class Test就是K;class Test1中就是T。
WildcardType接口 表示的是通配符泛型,通配符使用问号表示,例如:? extends Number和? super Integer。
接口中定义了2个方法。
GenericArrayType接口 表示的是数组类型,且数组中的元素是ParameterizedType或者TypeVariable。
例如:List[]或者T[]。
这个接口只有一个方法:
Type getGenericComponentType() 这个方法返回数组的组成元素。
类中定义泛型变量 语法:
1 2 class 类名<泛型变量1 ,泛型变量2 ,泛型变量3 extends 上边界1 ,泛型变量4 extends 上边界类型1 & 上边界类型2 & 上边界类型3 >
示例代码:
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 package h.xd.type;import java.lang.reflect.Type;import java.lang.reflect.TypeVariable;public class DemoClass <T1, T2 extends Integer , T3 extends DemoClass1 & DemoClass2> { public static void main (String[] args) { TypeVariable<Class<DemoClass>>[] typeParameters = DemoClass.class.getTypeParameters(); for (TypeVariable<Class<DemoClass>> typeParameter : typeParameters) { System.out.println("变量名称:" + typeParameter.getName()); System.out.println("这个变量在哪声明的:" + typeParameter.getGenericDeclaration()); Type[] bounds = typeParameter.getBounds(); System.out.println("这个变量上边界数量:" + bounds.length); System.out.println("这个变量上边界清单:" ); for (Type bound : bounds) { System.out.println(bound.getTypeName()); } System.out.println("--------------------" ); } } } interface DemoClass1 {} interface DemoClass2 {}
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 变量名称:T1 这个变量在哪声明的:class h .xd.type.DemoClass 这个变量上边界数量:1 这个变量上边界清单: java.lang.Object -------------------- 变量名称:T2 这个变量在哪声明的:class h .xd.type.DemoClass 这个变量上边界数量:1 这个变量上边界清单: java.lang.Integer -------------------- 变量名称:T3 这个变量在哪声明的:class h .xd.type.DemoClass 这个变量上边界数量:2 这个变量上边界清单: h.xd.type.DemoClass1 h.xd.type.DemoClass2 --------------------
方法中定义泛型变量 语法:
1 方法修饰符 <泛型变量1 ,泛型变量2 ,泛型变量3 extends 上边界1 ,泛型变量4 extends 上边界类型1 & 上边界类型2 & 上边界类型3 > 方法名称(参数1 类型 参数1 名称,参数2 类型 参数2 名称)
示例代码:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 package h.xd.type;import java.lang.reflect.Method;import java.lang.reflect.Type;import java.lang.reflect.TypeVariable;interface DemoFunction1 {} interface DemoFunction2 {} public class DemoFunction { public <T1, T2 extends Integer , T3 extends DemoFunction1 & DemoFunction2> T3 m1 (T1 t1, T2 t2, T3 t3, String s) { return t3; } public static void main (String[] args) { Method[] methods = DemoFunction.class.getDeclaredMethods(); Method m1 = null ; for (Method method : methods) { if (method.getName().equals("m1" )) { m1 = method; break ; } } System.out.println("m1方法参数类型列表信息:----------" ); Type[] genericParameterTypes = m1.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { if (genericParameterType instanceof TypeVariable) { TypeVariable pt = (TypeVariable) genericParameterType; System.out.println("变量类型名称:" + pt.getTypeName()); System.out.println("变量名称:" + pt.getName()); System.out.println("这个变量在哪声明的:" + pt.getGenericDeclaration()); Type[] bounds = pt.getBounds(); System.out.println("这个变量上边界数量:" + bounds.length); System.out.println("这个变量上边界清单:" ); for (Type bound : bounds) { System.out.println(bound.getTypeName()); } } else if (genericParameterType instanceof Class) { Class pt = (Class) genericParameterType; System.out.println("参数类型名称:" + pt.getTypeName()); System.out.println("参数类名:" + pt.getName()); } System.out.println("--------------------" ); } System.out.println("m1方法返回值类型信息:----------" ); Type genericReturnType = m1.getGenericReturnType(); if (genericReturnType instanceof TypeVariable) { TypeVariable pt = (TypeVariable) genericReturnType; System.out.println("变量名称:" + pt.getName()); System.out.println("这个变量在哪声明的:" + pt.getGenericDeclaration()); Type[] bounds = pt.getBounds(); System.out.println("这个变量上边界数量:" + bounds.length); System.out.println("这个变量上边界清单:" ); for (Type bound : bounds) { System.out.println(bound.getTypeName()); } System.out.println("--------------------" ); } System.out.println("m1方法中声明的泛型变量类型列表:----------" ); TypeVariable<Method>[] typeParameters = m1.getTypeParameters(); for (TypeVariable<Method> pt : typeParameters) { System.out.println("变量类型名称:" + pt.getTypeName()); System.out.println("变量名称:" + pt.getName()); System.out.println("这个变量在哪声明的:" + pt.getGenericDeclaration()); Type[] bounds = pt.getBounds(); System.out.println("这个变量上边界数量:" + bounds.length); System.out.println("这个变量上边界清单:" ); for (Type bound : bounds) { System.out.println(bound.getTypeName()); } System.out.println("--------------------" ); } } }
运行结果:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 m1方法参数类型列表信息:---------- 变量类型名称:T1 变量名称:T1 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:1 这个变量上边界清单: java.lang.Object -------------------- 变量类型名称:T2 变量名称:T2 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:1 这个变量上边界清单: java.lang.Integer -------------------- 变量类型名称:T3 变量名称:T3 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:2 这个变量上边界清单: h.xd.type.DemoFunction1 h.xd.type.DemoFunction2 -------------------- 参数类型名称:java.lang.String 参数类名:java.lang.String -------------------- m1方法返回值类型信息:---------- 变量名称:T3 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:2 这个变量上边界清单: h.xd.type.DemoFunction1 h.xd.type.DemoFunction2 -------------------- m1方法中声明的泛型变量类型列表:---------- 变量类型名称:T1 变量名称:T1 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:1 这个变量上边界清单: java.lang.Object -------------------- 变量类型名称:T2 变量名称:T2 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:1 这个变量上边界清单: java.lang.Integer -------------------- 变量类型名称:T3 变量名称:T3 这个变量在哪声明的:public h.xd.type.DemoFunction1 h.xd.type.DemoFunction.m1(java.lang.Object,java.lang.Integer,h.xd.type.DemoFunction1,java.lang.String) 这个变量上边界数量:2 这个变量上边界清单: h.xd.type.DemoFunction1 h.xd.type.DemoFunction2 --------------------
通配符类型 通配符在java中 使用?表示,例如:? extends Number和? super Integer。
java中通配符对应的类型是WildcardType接口,可以通过这个接口来获取通配符具体的各种信息。
通配符上边界 通配符具体的类型,可以任意指定,但是我们可以限定通配符的上边界,上边界指定了这个通配符能够表示的最大的范围的类型。
比如:?extends Integer,那么?对应的具体类型只能是Integer本身或者其子类型。
通配符下边界 也可以给通配符指定下边界,下边界定义了通配符能够表示的最小的类型。
比如:? super C1,那么?对应的具体类型只能是C1类型或者C1的父类型。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 package h.xd.type;import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.lang.reflect.WildcardType;import java.util.List;import java.util.Map;public class DemoWild { public static class C1 { } public static class C2 extends C1 { } public static List<?> m1(Map<? super C2, ? extends C1 > map) { return null ; } public static void main (String[] args) throws NoSuchMethodException { Method m1 = DemoWild.class.getMethod("m1" , Map.class); System.out.println("获取m1方法参数泛型详细参数信息" ); Type[] genericParameterTypes = m1.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { if (genericParameterType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericParameterType; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { if (actualTypeArgument instanceof WildcardType) { WildcardType wildcardType = (WildcardType) actualTypeArgument; System.out.println("通配符类型名称:" + wildcardType.getTypeName()); Type[] upperBounds = wildcardType.getUpperBounds(); for (Type upperBound : upperBounds) { System.out.println("通配符上边界类型:" + upperBound.getTypeName()); } Type[] lowerBounds = wildcardType.getLowerBounds(); for (Type lowerBound : lowerBounds) { System.out.println("通配符下边界类型:" + lowerBound.getTypeName()); } System.out.println("------------" ); } } } } System.out.println("获取m1方法返回值泛型类型详细信息" ); Type genericReturnType = m1.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericReturnType; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { if (actualTypeArgument instanceof WildcardType) { WildcardType wildcardType = (WildcardType) actualTypeArgument; System.out.println("通配符类型名称:" + wildcardType.getTypeName()); Type[] upperBounds = wildcardType.getUpperBounds(); for (Type upperBound : upperBounds) { System.out.println("通配符上边界类型:" + upperBound.getTypeName()); } Type[] lowerBounds = wildcardType.getLowerBounds(); for (Type lowerBound : lowerBounds) { System.out.println("通配符下边界类型:" + lowerBound.getTypeName()); } System.out.println("------------" ); } } } } }
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 获取m1方法参数泛型详细参数信息 通配符类型名称:? super h.xd.type.DemoWild$C2 通配符上边界类型:java.lang.Object 通配符下边界类型:h.xd.type.DemoWild$C2 ------------ 通配符类型名称:? extends h .xd.type.DemoWild$C1 通配符上边界类型:h.xd.type.DemoWild$C1 ------------ 获取m1方法返回值泛型类型详细信息 通配符类型名称:? 通配符上边界类型:java.lang.Object ------------
泛型数组 数组中的元素为泛型,那么这个数组就是泛型类型的数组,泛型数组在java中使用GenericArrayType接口来表示,可以通过这个接口提供的方法获取泛型数组更详细的信息。
如:List list []; List list [][];
泛型数组类型的可以作为方法的参数、方法的返回值、泛型类的具体类型、字段的类型等等。
示例代码:
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 33 34 35 36 37 package h.xd.type;import java.lang.reflect.Field;import java.lang.reflect.GenericArrayType;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.List;public class DemoList { List<String> list[]; public static void main (String[] args) throws NoSuchFieldException { Field list = DemoList.class.getDeclaredField("list" ); Type genericType = list.getGenericType(); System.out.println(genericType.getClass()); if (genericType instanceof GenericArrayType) { GenericArrayType genericArrayType = (GenericArrayType) genericType; Type genericComponentType = genericArrayType.getGenericComponentType(); System.out.println(genericComponentType.getClass()); if (genericComponentType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericComponentType; System.out.println(parameterizedType.getRawType()); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument.getTypeName()); } System.out.println(parameterizedType.getOwnerType()); } } } }
运行结果:
1 2 3 4 5 class sun .reflect.generics.reflectiveObjects.GenericArrayTypeImplclass sun .reflect.generics.reflectiveObjects.ParameterizedTypeImplinterface java .util.Listjava.lang.String null
综合案例 返回结果封装:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 public class CommonResult <T> { private long code; private String message; private T data; protected CommonResult () { } protected CommonResult (long code, String message, T data) { this .code = code; this .message = message; this .data = data; } public static <T> CommonResult<T> success (T data) { return new CommonResult <T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); } public static <T> CommonResult<T> success (T data, String message) { return new CommonResult <T>(ResultCode.SUCCESS.getCode(), message, data); } public static <T> CommonResult<T> failed (IErrorCode errorCode) { return new CommonResult <T>(errorCode.getCode(), errorCode.getMessage(), null ); } public static <T> CommonResult<T> failed (IErrorCode errorCode,String message) { return new CommonResult <T>(errorCode.getCode(), message, null ); } public static <T> CommonResult<T> failed (String message) { return new CommonResult <T>(ResultCode.FAILED.getCode(), message, null ); } public static <T> CommonResult<T> failed () { return failed(ResultCode.FAILED); } public static <T> CommonResult<T> validateFailed () { return failed(ResultCode.VALIDATE_FAILED); } public static <T> CommonResult<T> validateFailed (String message) { return new CommonResult <T>(ResultCode.VALIDATE_FAILED.getCode(), message, null ); } public static <T> CommonResult<T> unauthorized (T data) { return new CommonResult <T>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data); } public static <T> CommonResult<T> forbidden (T data) { return new CommonResult <T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data); } public long getCode () { return code; } public void setCode (long code) { this .code = code; } public String getMessage () { return message; } public void setMessage (String message) { this .message = message; } public T getData () { return data; } public void setData (T data) { this .data = data; } }