这是泛型第二篇文章,前面一篇文章全是概念知识。这篇文章就上一篇概念性知识举出示例进行讲解。
(补充一个知识点:instanceof详解,后面示例用了比较多instanceof关键字。)
一、泛型变量
泛型变量可以在类中和方法中定义。
泛型变量类型是使用TypeVariable接口来表示,所以可以通过TypeVariable接口获取泛型变量的所有信息。
1、类中定义泛型变量
语法:
class 类名<泛型变量1, 泛型变量2, 泛型变量3 extends 上边界1, 泛型变量4 extends 上边界1 & 上边界2 & 上边界3>
- 泛型变量需要在类名后面的括号中定义
- 每个类中可以定义多个泛型变量,多个泛型变量直接用逗号隔开
- 泛型变量可以通过extends关键字指定上边界,上边界可以对泛型变量起到限定作用,上边界可以指定0到多个,多个之间需要用&符号隔开,如果不指定上边界,默认上边界为Object类型
案例代码
package com.ydj.type;
import java.lang.reflect.*;
interface Demo1I1 { //@1
}
interface Demo1I2{ //@2
}
/**
* 类中泛型变量案例
* @param <T1>
* @param <T2>
* @param <T3>
*/
public class TypeDemo1<T1, T2 extends Integer, T3 extends Demo1I1 & Demo1I2> { //@3
public static void main(String[] args) {
TypeVariable<Class<TypeDemo1>>[] typeVariable = TypeDemo1.class.getTypeParameters(); //@4
for (TypeVariable<Class<TypeDemo1>> typeParameter : typeVariable) {
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("------------------");
}
}
}
代码解读:
- @1:创建接口Demo1I1,后面会用到
- @2:创建接口Demo1I2,后面会用到
- @3:创建了一个类TypeDemo1,注意这个类是泛型类型的,泛型中定义了3个泛型变量,分别是:T1、T2、T3,这三个变量是有区别的。
T1没有限制上边界,默认上边界就是Object类型了。
注意T2的写法:
T2 extends Integer
这个通过extends关键字限定了T2的上边界为Integer。
再看看T3的写法,比较特别:
T3 extends Demo1I1 & Demo1I2
T3的上边界有多个,多个上边界之间需要用 & 连接起来,T3有2个上边界,分别是两个接口Demo1I1和Demo1I2。
- @4:这行代码用来调用了Class对象的getTypeParameters方法,这个方法返回当前类上定义的泛型变量类型列表,当前类上定义了3个泛型变量类型,泛型变量类型在Java中使用TypeVariable接口表示。
后面的for循环就是输出泛型变量的信息了,我们来看一下运行效果:
变量名称:T1
这个变量在哪声明的:class com.ydj.type.TypeDemo1
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
------------------
变量名称:T2
这个变量在哪声明的:class com.ydj.type.TypeDemo1
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Integer
------------------
变量名称:T3
这个变量在哪声明的:class com.ydj.type.TypeDemo1
这个变量上边界数量:2
这个变量上边界清单:
com.ydj.type.Demo1I1
com.ydj.type.Demo1I2
------------------
输出中可以看到3个泛型变量都是在当前类TypeDemo1中定义的,每个泛型变量的名称以及泛型变量的上边界信息都详细输出来了。
2、方法中定义泛型变量
语法
方法修饰符 <泛型变量1, 泛型变量2, 泛型变量3 extends 上边界1, 泛型变量4 extends 上边界1 & 上边界2 & 上边界3> 方法名称(参数1类型 参数1名称, 参数2类型 参数2名称)
- 泛型变量需要在方法名称前面的括号中定义
- 方法中可以定义多个泛型变量,多个泛型变量之间用逗号隔开
- 泛型变量可以通过extends关键字指定上边界,上边界对泛型变量起到了限定作用,上边界可以指定0到多个,多个之间需要用 & 符号隔开,如果不指定上边界,默认上边界为Object类型
案例代码
package com.ydj.type;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
interface Demo2I1{ //@1
}
interface Demo2I2{ //@2
}
public class TypeDemo2 {
public <T1, T2 extends Integer, T3 extends Demo2I1 & Demo2I2>T3 m1 (T1 t1, T2 t2, T3 t3, String s){ //@3
return t3;
}
public static void main(String[] args) {
//获取TypeDemo2中声明的所有方法
Method[] methods = TypeDemo2.class.getDeclaredMethods();
Method m1 = null;
//找到m1方法
for (Method method : methods) {
if(method.getName().equals("m1")){
m1 = method;
break;
}
}
//获取方法的泛型参数列表
System.out.println("----------m1方法参数类型列表信息:----------");
Type[] genericParameterTypes = m1.getGenericParameterTypes();
for (Type genericParameterType :genericParameterTypes) {
//3个参数都是泛型变量类型的,对应Java中的TypeVariable
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);
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:这行比较特别,创建了一个方法,如下:
public <T1, T2 extends Integer, T3 extends Demo2I1 & Demo2I2> T3 m1(T1 t1, T2 t2, T3 t3, String s)
m1方法前面的<>括号中定义了3个泛型类型变量,方法有4个参数,前3个参数的类型为泛型变量类型,第4个参数为String类型。
泛型变量类型在Java中使用TypeVariable表示,前3个参数都是泛型变量类型,所以最后他们的信息都可以使用TypeVariable接口获取,最后一个参数是String类型,这个是非泛型类型,使用Class类型表示。
上面代码中先获取m1方法对应的Method对象,然后通过Method中的方法获取了方法参数的列表、方法的返回值详细的泛型信息、方法中声明的3个泛型变量的详细信息。
结果如下:
----------m1方法参数类型列表信息:----------
变量类型名称:T1
变量名称:T1
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:1
java.lang.Object
------------------
变量类型名称:T2
变量名称:T2
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:1
java.lang.Integer
------------------
变量类型名称:T3
变量名称:T3
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:2
com.ydj.type.Demo2I1
com.ydj.type.Demo2I2
------------------
参数类型名称:java.lang.String
参数名称:java.lang.String
------------------
----------m1方法返回值类型信息:----------
变量名称:T3
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:2
这个变量上边界清单
com.ydj.type.Demo2I1
com.ydj.type.Demo2I2
------------------
----------m1方法中声明的泛型变量类型列表:----------
变量类型名称:T1
变量名称:T1
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
--------------------
变量类型名称:T2
变量名称:T2
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Integer
--------------------
变量类型名称:T3
变量名称:T3
这个变量在哪声明的:public com.ydj.type.Demo2I1 com.ydj.type.TypeDemo2.m1(java.lang.Object,java.lang.Integer,com.ydj.type.Demo2I1,java.lang.String)
这个变量上边界数量:2
这个变量上边界清单:
com.ydj.type.Demo2I1
com.ydj.type.Demo2I2
--------------------
二、泛型类型
泛型类型定义的语法
具体类型<类型1, 类型2, 类型3>
- 泛型类型可以作为方法的参数、方法的返回值、泛型类(这3种会一一举例)
- <>中的泛型的实际参数列表,可以有多个,可以是任意类型的。比如:String类型、自定义类型、泛型变量类型、泛型通配符类型(?表示通配符)
- 泛型类型的信息在Java中使用ParameterizedType接口来表示,可以通过这个接口作为入口获取泛型的具体详细信息。
比如:List< String >、Map< Integer, String >、UserMapper< UserModel >,这些都是泛型类型,这些泛型的信息都可以通过ParameterizedType来表示,然后通过这个接口中的方法获取这些泛型的具体信息。
下面来详解3种泛型类型。
1、方法中泛型参数和泛型返回值
方法的参数为泛型类型或者返回值为泛型类型,我们来获取这些泛型类型的信息。
案例代码
package com.ydj.type;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
public class TypeDemo3<T> { //@0
public class C1{ //@1
/**
* m1方法参数和返回值都是泛型类型,泛型的实际类型是泛型变量类型T,T是在TypeDemo3中声明的
* @param list
* @return
*/
public List<T> m1(List<T> list){ //@2
//对list做一些操作
return list;
}
}
public static void main(String[] args) throws NoSuchMethodException {
//获取m1方法
Method m1 = TypeDemo3.class.getMethod("m1", List.class);
//调用Method中getGenericParameterTypes方法可以获取参数类型列表,包含了详细的泛型信息
Type arg1Tyep = m1.getGenericParameterTypes()[0];
//m1方法有1个参数是泛型类型的,泛型类型Java中用ParameterizedType接口表示
System.out.println("----------m1方法参数类型信息------------");
if (arg1Tyep instanceof ParameterizedType){ //@3
ParameterizedType parameterizedType = (ParameterizedType) arg1Tyep;
System.out.println("原始类型:" + parameterizedType.getRawType());
System.out.println("所属的类型:" + parameterizedType.getOwnerType());
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//泛型中第一个参数的类型是T,T是泛型变量,泛型变量对应Java中的TypeVariable接口
Type oneType = actualTypeArguments[0]; //@4
System.out.println("@5:" + oneType.getClass()); //@5
if(oneType instanceof TypeVariable){
System.out.println("这个参数是个泛型变量类型!");
TypeVariable<Class<TypeDemo3>> oneActualType = (TypeVariable) oneType;
System.out.println("变量名称:" + oneActualType.getName());
System.out.println("这个变量在哪声明的:" + oneActualType.getGenericDeclaration());
Type[] bounds = oneActualType.getBounds();
System.out.println("这个变量上边界数量:" + bounds.length);
System.out.println("这个变量上边界清单:");
for (Type bound:bounds) {
System.out.println(bound.getTypeName());
}
}
}
System.out.println("----------m1方法返回值类型信息------------");
//m1方法返回值是泛型类型的,泛型类型Java中用ParameterizedType接口表示
//Method类中的getGenericReturnType方法可以获取方法的返回值,如果返回值是泛型类型的,会获取泛型类型对应的具体类型
Type returnType = m1.getGenericReturnType();
if(returnType instanceof ParameterizedType){ //@6
ParameterizedType parameterizedType = (ParameterizedType) returnType;
System.out.println("原始类型:" + parameterizedType.getRawType());
System.out.println("所属的类型:" + parameterizedType.getOwnerType());
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//泛型中第一个参数的类型是T,T是泛型变量,泛型变量对应Java中的TypeVariable接口
Type oneType = actualTypeArguments[0]; //@7
System.out.println("@8:" + oneType.getClass()); //@8
if (oneType instanceof TypeVariable) {
System.out.println("返回值是个泛型变量类型!");
TypeVariable<Class<TypeDemo3>> oneActualType = (TypeVariable) oneType;
System.out.println("变量名称:" + oneActualType.getName());
System.out.println("这个变量在哪声明的:" + oneActualType.getGenericDeclaration());
Type[] bounds = oneActualType.getBounds();
System.out.println("这个变量上边界数量:" + bounds.length);
System.out.println("这个变量上边界清单:");
for (Type bound : bounds) {
System.out.println(bound.getTypeName());
}
System.out.println("--------------------");
}
}
}
}
代码解读
- @0:TypeDemo3< T >声明了一个泛型类型的变量T;T是个泛型类型的变量,泛型类型的变量在Java中使用TypeVariable来表示
- @1:创建了一个类C1,注意这个类是在TypeDemo3的内部声明的,说明C1是一个内部类
- @2:创建了一个方法m1,m1的参数和返回值都是泛型类型的List< T >,泛型类型在Java中用ParameterizedType接口表示;而List< T >泛型类型中还有一个类型T,T是泛型变量类型的,在Java中使用TypeVariable接口表示
上面代码中输出了m1方法参数的泛型的详细信息,结果如下:
----------m1方法参数类型信息------------
原始类型:interface java.util.List
所属的类型:null
@5:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
这个参数是个泛型变量类型!
变量名称:T
这个变量在哪声明的:class com.ydj.type.TypeDemo3
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
----------m1方法返回值类型信息------------
原始类型:interface java.util.List
所属的类型:null
@8:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
返回值是个泛型变量类型!
变量名称:T
这个变量在哪声明的:class com.ydj.type.TypeDemo3
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
--------------------
2、泛型类
泛型类的定义
类修饰符 类名<类型1, 类型2, 类型n>{
}
上面是定义了一个泛型类,<>中包含的是一些可以变类型的列表,实际上我们创建这个类的对象的时候,会明确指定<>中包含的具体类型。
比如我们熟悉的HashMap就是一个泛型类,来看看这个类的定义:
public class HashMap<K, V>
K和V是泛型变量类型的,具体是什么类型,可以在创建HashMap的时候去随意指定。
现在我们想获取泛型对象<>中包含的具体的类型,怎么获取呢?
比如下面代码:
package com.ydj.type;
public class TypeDemo4<T1, T2> { //@1
public void m1(TypeDemo4<T1, T2> demo){ //@2
System.out.println(demo.getClass());
}
public static void main(String[] args) {
TypeDemo4<String, Integer> demo4 = new TypeDemo4<>(); //@3
demo4.m1(demo4);
}
}
- @1:TypeDemo4类中定义了两个泛型变量类型T1和T2
- @2:m1方法参数类型为TypeDemo4,在这个方法内部,如果我们想获取这个参数具体的详细类型信息,上面的代码是获取不到的,只能获取到demo4参数所属的类型是TypeDemo4,但是无法获取到TypeDemo4中的T1和T2这两个泛型变量类型对应的具有类型。
运行一下上面代码,结果如下:
class com.ydj.type.TypeDemo4
Class对象中有个方法比较牛逼:
public Type getGenericSuperclass()
这个方法相当牛逼,可以获取到父类中泛型详细信息。
来看一个案例就明白了:
package com.ydj.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class Demo<T1, T2>{ //@0
}
public class TypeDemo5 extends Demo<String, Integer> { //@1
public static void main(String[] args) {
TypeDemo5 demo5 = new TypeDemo5();
//demo5Class对应的是TypeDemo5的Class对象
Class<? extends TypeDemo5> demo5Class = demo5.getClass(); //@2
//获取TypeDemo5的父类的详细信息,包含泛型信息
Type genericSuperclass = demo5Class.getGenericSuperclass(); //@3
//泛型类型用ParameterizedType接口表示,输出看一下是不是这个接口类型
System.out.println(genericSuperclass.getClass()); //@4
if(genericSuperclass instanceof ParameterizedType){ //@5
ParameterizedType pt = (ParameterizedType) genericSuperclass;
System.out.println("父类原始类型:" + pt.getRawType());
Type[] actualTypeArguments = pt.getActualTypeArguments();
for (Type actualTypeArgument:actualTypeArguments) {
System.out.println(actualTypeArgument.getTypeName());
}
System.out.println("父类所属类型:" + pt.getOwnerType());
}
}
}
运行输出:
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
父类原始类型:class com.ydj.type.Demo
java.lang.String
java.lang.Integer
父类所属类型:null
- @0:声明了一个泛型类,泛型类中定义了两个泛型变量的类型T1和T2,这两个变量的具体类型,可以在创建对象的时候指定任意具体的类型
- @1:这个比较特殊了,创建了TypeDemo5,这个类继承了Demo类,并且注意Demo后面的部分< String, Integer >,这个指定了具体的类型了,此时T1的具体类型就是String类型了,T2对应的具体类型就是Integer类型了
- @2:获取TypeDemo5对应的Class对象
- @3:这行代码比较关键,这个调用了Class类中的getGenericSupperclass方法,这个方法可以获取当前父类的具体类型信息,如果父类是泛型,则会返回泛型详细信息,泛型类型在Java中用ParameterizedType接口表示,所以@3代码返回的类型一定是ParameterizedType接口类型了
- @4:输出了genericSuperclass变量的类型,注意上面第2行输出:ParameterizedTypeImpl,这个是ParameterizedType接口的一个实现类。
- @5:这个地方加了一个判断,判断是不是ParameterizedType类型的,然后if内部输出了整个泛型类型的具体的信息,调用了ParameterizedType接口中的3个方法去获取了具体的参数类型的信息,输出中的5、6行可以看到输出了具体的类型String和Integer。
根据上面代码的原理,我们可以将下面的代码进行改造:
package com.ydj.type;
public class TypeDemo4<T1, T2> { //@1
public void m1(TypeDemo4<T1, T2> demo){ //@2
System.out.println(demo.getClass());
}
public static void main(String[] args) {
TypeDemo4<String, Integer> demo4 = new TypeDemo4<>(); //@3
demo4.m1(demo4);
}
}
如果我们想获得TypeDemo4的具体信息,需要给TypeDemo4创建一个子类才可以,此处我们可以使用Java中的匿名内部类来友好地解决这个问题,将上面代码变换一下,变成下面这样:
package com.ydj.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class TypeDemo4<T1, T2> { //@1
public void m1(TypeDemo4<T1, T2> demo){ //@2
//demo4Class对应的是TypeDemo4的Class对象
Class<? extends TypeDemo4> demo4Class = demo.getClass();
//获取demo父类的详细类型信息,包含泛型信息
Type genericSuperclass = demo4Class.getGenericSuperclass();
//泛型类型用ParameterizedType接口表示,输出看下这个接口类型
System.out.println(genericSuperclass.getClass());
if(genericSuperclass instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType)genericSuperclass;
System.out.println("原始类型:" + pt.getRawType());
Type[] actualTypyArguments = pt.getActualTypeArguments();
for (Type actualTypeArgument: actualTypyArguments) {
System.out.println(actualTypeArgument.getTypeName());
}
System.out.println("所属类型:" + pt.getOwnerType());
}
}
public static void main(String[] args) {
TypeDemo4<String, Integer> demo4 = new TypeDemo4<String, Integer>(){
}; //@3
demo4.m1(demo4);
}
}
关键代码在@3,这个地方利用了一个匿名内部类,相当于创建了TypeDemo4的一个子类,并且指定了TypeDemo4中两个泛型变量类型的具体类型。
运行代码输出如下:
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
原始类型:class com.ydj.type.TypeDemo4
java.lang.String
java.lang.Integer
所属类型:null
这次我们获取到了泛型类中具体的类型了。
这种玩法在fastjson中有用到,再来看个案例:
package com.ydj.type;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.*;
import java.io.Serializable;
public class TypeDemo6 {
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Result<T> implements Serializable{ //@1
private String code;
private String subCode;
private String msg;
private T data;
}
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UserModel{ //@2
private Integer id;
private String name;
}
/**
* 返回一个用户信息
*
* @return
*/
public static Result<UserModel> getUser(){ //@3
UserModel userModel = UserModel.builder().id(1).name("xxxx").build();
Result<UserModel> result = Result.<UserModel>builder().code("1").subCode(null).msg("操作成功").data(userModel).build();
return result;
}
/**
* 返回用户Json格式信息
*
* @return
*/
public static String getUserString(){ //@4
return JSON.toJSONString(getUser());
}
public static void main(String[] args) {
String userString = getUserString();
//会输出:{"code":"1","data":{"id":1,"name":"xxxx"},"msg":"操作成功"}
System.out.println(userString); //@5
//下面我们需要将userString反序列化为Result<UserModel>对象
Result<UserModel> userModelResult = JSON.parseObject(userString, new TypeReference<Result<UserModel>>(){
}); //@6
//我们来看看Result中的data是不是UserModel类型的
System.out.println(userModelResult.getData().getClass()); //@7
}
}
先看看运行结果:
{"code":"1","data":{"id":1,"name":"xxxx"},"msg":"操作成功"}
class com.ydj.type.TypeDemo6$UserModel
- @1:创建了一个Result类型的,这个类型可以作为任何接口通用的返回值类型,这个大家可以借鉴。接口有几个通用的字段:code(状态码),subCode(子状态码),data(具体的任何类型的数据,data的具体类型可以在Result的时候指定),msg(接口返回的提示信息,如错误提示或操作成功等信息)
- @2:创建了一个用户类
- @3:这个方法模拟返回一个用户信息,用户信息封存在Result中
- @4:将用户信息转换为json字符串返回
- @5:输出了用户信息字符串,也就是上面输出中的第一行内容
- @6:这个是上面代码的关键,调用了fastjson中的方法,将字符串反序列化为Result< UserModel >,fastjson是如何获取泛型类Result中的T的具体类型的呢?T具体的类型对应的是UserModel,关键代码就是下面这行代码:
new TypeReference<Result<UserModel>>{
}
这个相当于创建了一个TypeReference类的一个子类,注意TypeReference后面尖括号中的东西,是< UserModel >,通过这个指定了泛型变量类型的具体类型,我们去看一下TypeReference类源码,贴出来一些关键代码:
public class TypeReference<T>{
protected TypeReference(){
Type superClass = this.getClass().getGenericSuperclass(); //@1
Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0]; //@2
Type cachedType = (Type)classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = (Type)classTypeCache.get(type);
}
this.type = cachedType;
}
}
注意上面的@1和@2是不是很熟悉了,fastjson中获取泛型的具体类型也是让我们采用匿名类去实现的,最后内部也是调用getGenericSuperclass去获取具体的泛型类型中具体的类型的。
3、通配符类型
通配符在Java中使用 ?表示,例如:? extends Number 和 ? super Integer。
Java中通配符对应的类型是WildcardType接口,可以通过这个接口来获取通配符具体的各种信息。
通配符上边界
通配符具体的类型,可以任意指定,但是我们可以限定通配符的上边界,上边界指定了这个通配符能够表示的最大的范围的类型。
比如:? extends Integer,那么 ?对应的具体类型只能是Integer本身或者其子类型。
通配符下边界
也可以给通配符指定下边界,下边界定义了通配符能够表示的最小的类型。
比如:? super C1,那么 ?对应的具体类型只能是C1类型或者C1的父类型。
package com.ydj.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 TypeDemo7 {
public static class C1{} //@1
public static class C2 extends C1{} //@2
public static List<?> m1(Map<? super C2, ? extends C1> map){ //@3
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//获取m1方法
Method m1 = TypeDemo7.class.getMethod("m1", Map.class);
//获取m1方法参数泛型详细参数信息
System.out.println("-------------获取m1方法参数泛型详细参数信息-------------");
Type[] genericParameterTypes = m1.getGenericParameterTypes();
for (Type genericParameterType:genericParameterTypes) {
//m1的参数为Map<? super C2, ? extends C1>,这个是泛型类型的,所以是ParameterizedType接口类型
if(genericParameterType instanceof ParameterizedType){ //@4
ParameterizedType pt = (ParameterizedType)genericParameterType;
//下面获取Map后面两个尖括号中的泛型参数列表,对应? super C2和? extends C1这部分内容
//这部分内容在Java中对应WildcardType接口类型
Type[] actualTypeArguments = pt.getActualTypeArguments();
for (Type actualTypeArgument:actualTypeArguments) {
if(actualTypeArgument instanceof WildcardType){
WildcardType wt = (WildcardType)actualTypeArgument;
//获取通配符的名称,输出是?
System.out.println("通配符类型名称:" + wt.getTypeName());
//获取通配符的上边界
Type[] upperBounds = wt.getUpperBounds();
for (Type upperBound:upperBounds) {
System.out.println("通配符上边界类型:" + upperBound.getTypeName());
}
//获取通配符的上边界
Type[] lowerBounds = wt.getUpperBounds();
for (Type lowerBound:lowerBounds) {
System.out.println("通配符下边界类型:" + lowerBound.getTypeName());
}
System.out.println("----------------");
}
}
}
}
//获取返回值通配符详细信息
System.out.println("-------------获取m1方法返回值泛型类型详细信息-------------");
Type genericReturnType = m1.getGenericReturnType();
// m1的返回值是List<?>,这个是个泛型类型,对应ParameterizedType接口,泛型中的具体类型是个通配符类型,通配符对应WildcardType接口类型
if (genericReturnType instanceof ParameterizedType) { //@4
ParameterizedType parameterizedType = (ParameterizedType) genericReturnType; //@5
//下面获取List面两个尖括号中的泛型参数列表,对应?这部分的内容,这个是个通配符类型,这部分在java中对应WildcardType接口
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("------------");
}
}
}
}
}
结果为:
-------------获取m1方法参数泛型详细参数信息-------------
通配符类型名称:? super com.ydj.type.TypeDemo7$C2
通配符上边界类型:java.lang.Object
通配符下边界类型:java.lang.Object
----------------
通配符类型名称:? extends com.ydj.type.TypeDemo7$C1
通配符上边界类型:com.ydj.type.TypeDemo7$C1
通配符下边界类型:com.ydj.type.TypeDemo7$C1
----------------
-------------获取m1方法返回值泛型类型详细信息-------------
通配符类型名称:?
通配符上边界类型:java.lang.Object
------------
具体的就不解释了,和上面的案例类似。只需要注意一点 ?通配符的信息使用WildcardType接口表示,可以通过这个接口获取通配符的详细信息。
三、泛型数组
什么是泛型数组?
数组中的元素为泛型,那么这个数组就是泛型类型的数组,泛型数组在Java中使用GenericArrayType接口表示,可以通过这个接口提供的方法获取泛型数组更详细的信息。
如:List< String > list [];List< String > list [][];
泛型数组类型的可以作为方法的参数、方法的返回值、泛型类的具体类型、字段的类型等待…
下面就以泛型字段来举例,一起来获取泛型字段的详细信息吧!
package com.ydj.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 TypeDemo8 {
List<String> list[]; //@1
public static void main(String[] args) throws NoSuchFieldException {
//通过反射包里面的Field类和Class类获取方法所有信息
Field list = TypeDemo8.class.getDeclaredField("list");
//获取字段的泛型类型
Type genericType = list.getGenericType(); //@2
//看看字段的具体泛型类型
System.out.println(genericType.getClass()); //@3
if (genericType instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) genericType;
//获取数组的具体类型,具体的类型就是List<String>,这个是个泛型类型,对应java中的ParameterizedType接口
Type genericComponentType = genericArrayType.getGenericComponentType();//@4
System.out.println(genericComponentType.getClass());
if (genericComponentType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericComponentType;
System.out.println("原始类型:" + parameterizedType.getRawType());
//调用getActualTypeArguments()获取List<String>中尖括号中的参数列表
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//@5
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument.getTypeName());
}
System.out.println("所属类型:" + parameterizedType.getOwnerType());
}
}
}
}
运行输出:
class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
原始类型:interface java.util.List
java.lang.String
所属类型:null
代码解读
- @1:声明了一个泛型类型的数组
- @2:获取list字段对应的泛型数组类型,泛型数组在Java中使用GenericArrayType表示,所以@3输出的是GenericArrayType接口类型的
- @4:调用了GenericArrayType接口中的getGenericComponentType方法,会返回数组的具体的泛型类型,这个地方对应的就是List< String >,这个是个泛型类型,泛型类型在Java中使用ParameterizedType接口表示
- @5:调用了ParameterizedType接口中的getActualTypeArguments方法,这个方法可以获取泛型类型中具体的类型列表,就是List< String >中的String参数列表
四、综合案例
package com.ydj.type;
import java.util.List;
import java.util.Map;
public class TypeDemo9<K, V> {
Map<String, ? extends List<? extends Map<K,V>>> [][] map;
}
上面这个看似几条语句,但是挺复杂的,我们一步步拆解解析,步骤如下:
1、TypeDemo9:对应Java中的Class对象
2、<K, V>:定义了2个泛型变量,泛型变量对应Java中的TypeVariable接口
3、Map<String, ? extends List<? extends Map<K, V>>> [][] map:定义了一个二维泛型数组,泛型数组在Java中用GenericArrayType接口表示
4、mp中的每个元素是这个Map<String, ? extends List<? extends Map<K, V>>> []类型的,是一个一维泛型数组,泛型数组在Java中用GenericArrayType接口表示
5、再继续拆解,Map<String, ? extends List<? extends Map<K, V>>> []中每个元素都是Map<String, ? extends List<? extends Map<K, V>>>泛型类型的,泛型类型在Java中用ParameterizedType接口表示
6、拆解Map<String, ? extends List<? extends Map<K, V>>>这个泛型类型中<>尖括号里面的参数列表,可以调用ParameterizedType接口的Type[] getActualTypeArguments()方法获取Map<String, ? extends List<? extends Map<K, V>>>泛型类型中<>尖括号里面的2个参数,分别是String和? extends List<? extends Map<K, V>>
7、String是Java中定义的类型,对应Java中的Class对象
8、? extends List<? extends Map<K, V>>是通配符类型的,对应Java中的WildcardType接口,通配符指定了上边界,上边界是List<? extends Map<K, V>>
9、List<? extends Map<K, V>>又是一个泛型类型,泛型类型在Java中用ParameterizedType接口表示;List<? extends Map<K, V>>中<>尖括号里面又定义了这个泛型类型的具体的类型 ? extends Map<K, V>
10、? extends Map<K, V>又是一个通配符类型,对应Java中WildcardType接口,这个通配符指定了上边界为Map<K, V>
11、Map<K, V>又是一个泛型类型,泛型类型对应Java中的ParameterizedType接口,调用这个接口的Type[] getActualTypeArguments()方法获取泛型中的参数列表K和V
12、K和V是TypeDemo9中定义的泛型变量类型,泛型变量类型对应Java中的TypeVariable接口
按照上面的思路,我们来完善一下代码:
package com.ydj.type;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
public class TypeDemo9<K, V> {
Map<String, ? extends List<? extends Map<K,V>>> [][] map;
public static void parseType(Type type, int level) {
String whileString = whileString(level);
//1、泛型数组类型
if (type instanceof GenericArrayType) {
System.out.println(whileString + "泛型数组类型:" + type);
parseType(((GenericArrayType) type).getGenericComponentType(), ++level);
} else if (type instanceof ParameterizedType) {//泛型类型
System.out.println(whileString + "泛型类型:" + type);
ParameterizedType parameterizedType = (ParameterizedType) type;
System.out.println(whileString + "原始类型:" + parameterizedType.getRawType());
//获取泛型参数的详细信息
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(whileString + actualTypeArguments.length + "个泛型参数,如下:");
int count = 0;
for (Type actualTypeArgument : actualTypeArguments) {
if (count++ == 0) {
level++;
}
parseType(actualTypeArgument, level);
}
} else if (type instanceof WildcardType) {//通配符类型
System.out.println(whileString + "通配符类型:" + type);
WildcardType wildcardType = (WildcardType) type;
System.out.println(whileString + "通配符类型名称:" + wildcardType.getTypeName());
Type[] upperBounds = wildcardType.getUpperBounds();
System.out.println(whileString + "上边界列表:");
int count = 0;
for (Type upperBound : upperBounds) {
if (count++ == 0) {
level++;
}
parseType(upperBound, level);
}
System.out.println(whileString + "下边界列表:");
Type[] lowerBounds = wildcardType.getLowerBounds();
for (Type lowerBound : lowerBounds) {
if (count++ == 0) {
level++;
}
parseType(lowerBound, level);
}
} else if (type instanceof TypeVariable) {//泛型变量类型
System.out.println(whileString + "泛型变量类型:" + type);
TypeVariable typeVariable = (TypeVariable) type;
Type[] bounds = typeVariable.getBounds();
System.out.println(whileString + "泛型变量上边界列表:");
int count = 0;
for (Type bound : bounds) {
if (count++ == 0) {
level++;
}
parseType(bound, level);
}
} else if (type instanceof Class) {//普通类型
System.out.println(whileString + "普通类型:" + ((Class) type).getName());
}
}
/**
* 根据“----”符号,来对比泛型级别,分别阅读和区分
*
* @param count 级别
* @return
*/
public static String whileString(int count){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < count; i++){
sb.append("----");
}
return sb.toString();
}
public static void main(String[] args) throws NoSuchFieldException {
//获取TypeDemo9的字段信息
Field field = TypeDemo9.class.getDeclaredField("map");
Type genericType = field.getGenericType();
parseType(genericType, 0);
}
}
运行输出:
泛型数组类型:java.util.Map<java.lang.String, ? extends java.util.List<? extends java.util.Map<K, V>>>[][]
----泛型数组类型:java.util.Map<java.lang.String, ? extends java.util.List<? extends java.util.Map<K, V>>>[]
--------泛型类型:java.util.Map<java.lang.String, ? extends java.util.List<? extends java.util.Map<K, V>>>
--------原始类型:interface java.util.Map
--------2个泛型参数,如下:
------------普通类型:java.lang.String
------------通配符类型:? extends java.util.List<? extends java.util.Map<K, V>>
------------通配符类型名称:? extends java.util.List<? extends java.util.Map<K, V>>
------------上边界列表:
----------------泛型类型:java.util.List<? extends java.util.Map<K, V>>
----------------原始类型:interface java.util.List
----------------1个泛型参数,如下:
--------------------通配符类型:? extends java.util.Map<K, V>
--------------------通配符类型名称:? extends java.util.Map<K, V>
--------------------上边界列表:
------------------------泛型类型:java.util.Map<K, V>
------------------------原始类型:interface java.util.Map
------------------------2个泛型参数,如下:
----------------------------泛型变量类型:K
----------------------------泛型变量上边界列表:
--------------------------------普通类型:java.lang.Object
----------------------------泛型变量类型:V
----------------------------泛型变量上边界列表:
--------------------------------普通类型:java.lang.Object
--------------------下边界列表:
------------下边界列表:
上面将map这个属性详细的泛型信息都输出来了,重点在于上面的parseType方法。Java中的类型无非就是5种表示类型,这个方法内部使用递归来解析这些类型。
总结
泛型解析需要一步步拆解,会被拆解为5中类型中的一种,需要理解5种类型分别对应什么,这是关键。
你如果认真看到这里,再回过头看看第一篇开头出现的那幅图,可能会更加明白一点哦。