输出中可以看到3个泛型变量都是在当前类Demo1中定义的,每个泛型变量的名称,以及泛型变量的上边界信息都详细输出来了。
方法中定义泛型变量
语法
方法修饰符 <泛型变量1,泛型变量2,泛型变量3 extends 上边界1,泛型变量4 extends 上边界类型1 & 上边界类型2 & 上边界类型3> 方法名称(参数1类型 参数1名称,参数2类型 参数2名称)
-
泛型变量需要在方法名称前面的括号中定义
-
方法中可以定义多个泛型变量,多个泛型变量之间用逗号隔开
-
泛型变量可以通过extends关键字指定上边界,上边界可以对泛型变量起到了限定的作用,上边界可以指定0到多个,多个之间需要用&符号隔开,如果不指定上边界,默认上边界为Object类型
案例代码
package com.javacode2018.chat05.demo11;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
interface Demo2I1 { //@1
}
interface Demo2I2 { //@2
}
/**
* 泛型方法中的泛型变量
*/
public class Demo2 {
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) {
//获取Demo2中声明的所有方法
Method[] methods = Demo2.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);
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[] typeParameters = m1.getTypeParameters();
for (TypeVariable 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个泛型变量的详细信息。
泛型类型
泛型类型定义的语法
具体类型<类型1,类型2,类型3>
-
泛型类型可以作为方法的参数、方法的返回值、泛型类(这3种一会举例)
-
<>中的泛型的实际参数列表,可以有多个,可以是任意类型的,比如:String类型、自定义类型、泛型变量类型、泛型通配符类型(?表示通配符,这个一会后面会讲)
-
泛型类型的信息在java中使用ParameterizedType接口来表示,可以通过这个接口作为入口获取泛型的具体详细信息。
比如:List、Map<Integer,String>、UserMapper,List这些都是泛型类型,这些泛型的信息都可以通过ParameterizedType来表示,然后通过这个接口中的方法获取这些泛型的具体信息。
下面来详解3种泛型类型。
方法中泛型参数和泛型返回值
方法的参数为泛型类型或者返回值为泛型类型,我们来获取这些泛型类型的信息。
案例代码
package com.javacode2018.chat05.demo11;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.stream.Collectors;
/**
* 泛型参数
*/
public class Demo4 {//@0
public class C1 {//@1
/**
* m1方法参数和返回值都是泛型类型,泛型的实际类型是泛型变量类型T,T是在Demo4中声明的
* @param list
* @return
*/
public List m1(List list) {//@2
//对list做一些操作
return list;
}
}
public static void main(String[] args) throws NoSuchMethodException {
//获取m1方法
Method m1 = Demo4.C1.class.getMethod(“m1”, List.class);
//调用Method中的getGenericParameterTypes方法可以获取参数类型列表,包含了详细的泛型信息
Type arg1Type = m1.getGenericParameterTypes()[0];
//m1方法有1个参数是泛型类型的,泛型类型java中用ParameterizedType接口表示
System.out.println(“----------m1方法参数类型信息------------”);
if (arg1Type instanceof ParameterizedType) {//@3
ParameterizedType parameterizedType = (ParameterizedType) arg1Type;
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> 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方法可以获取方法的返回值,如果返回值是泛型类型的,会获取泛型类型对应的具体类型,此处返回的是List类型的,java中使用ParameterizedType接口表示
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> 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:Demo1声明了一个泛型类型的变量T;T是个泛型类型的变量,泛型类型的变量在java中使用TypeVariable来表示。
@1:创建了一个类C1,注意这个类是在Demo1的内部声明的,说明C1是一个内部类。
@2:创建了方法m1,m1的参数和返回值都是泛型类型的List,泛型类型在java中用ParameterizedType接口表示;而List泛型类型中还有一个类型T,T是泛型变量类型的,在java中使用TypeVariable接口表示。
上面代码中输出了m1方法参数的泛型的详细信息。
我们来运行看一下结果:
----------m1方法参数类型信息------------
原始类型:interface java.util.List
所属的类型:null
@5:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
这个参数是个泛型变量类型!
变量名称:T
这个变量在哪声明的:class com.javacode2018.chat05.demo11.Demo4
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
----------m1方法返回值类型信息------------
原始类型:interface java.util.List
所属的类型:null
@8:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
返回值是个泛型变量类型!
变量名称:T
这个变量在哪声明的:class com.javacode2018.chat05.demo11.Demo4
这个变量上边界数量:1
这个变量上边界清单:
java.lang.Object
泛型类
泛型类的定义
类修饰符 类名<类型1,类型2,类型n>{
}
上面是定义了一个泛型类,<>中包含的是一些可以变类型的列表,实际上我们创建这个类的对象的时候,会明确指定<>中包含的具体类型。
比如我们熟悉的HashMap就是一个泛型类,来看看这个类的定义:
public class HashMap<K,V>
K和V是泛型变量类型的,具体是什么类型,可以在创建HashMap的时候去随意指定。
现在我们想获取泛型对象<>中包含的具体的类型,怎么获取?
比如下面代码:
package com.javacode2018.chat05.demo11;
public class Demo5<T1, T2> { //@1
public void m1(Demo5<T1, T2> demo) { //@2
System.out.println(demo.getClass());
}
public static void main(String[] args) {
Demo5<String, Integer> demo5 = new Demo5<>();//@3
demo5.m1(demo5);
}
}
@1:Demo5类中定义了两个泛型变量类型T1和T2。
@2:m1方法参数类型为Demo5,在这个方法内部如果我们想获取这个参数具体的详细类型信息,上面的代码是获取不到的,只能获取到demo5参数所属的类型是Demo5,但是无法获取到Demo5中的T1和T2这两个泛型变量类型对应的具体类型。
运行一下上面代码输出:
class com.javacode2018.chat05.demo11.Demo5
Class对象中有个方法比较牛逼:
public Type getGenericSuperclass()
这个方法相当牛逼,可以获取到父类中泛型详细信息。
来看一个案例就明白了:
package com.javacode2018.chat05.demo11;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
//泛型类
class Demo<T1, T2> {//@0
}
public class Demo6 extends Demo<String, Integer> { //@1
public static void main(String[] args) {
Demo6 demo6 = new Demo6();
//demo6Class对应的是Demo6的Class对象
Class<? extends Demo6> demo6Class = demo6.getClass();//@2
//获取Demo6的父类的详细类型信息,包含泛型信息
Type genericSuperclass = demo6Class.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());
}
}
}
运行输出:
com.javacode2018.chat05.demo11.Demo6
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class com.javacode2018.chat05.demo11.Demo
java.lang.String
java.lang.Integer
null
代码解读:
@0:声明了一个泛型类,泛型类中定义了两个泛型变量的类型T1和T2,这两个变量的具体类型,可以在创建对象的时候指定任意具体的类型。
@1:这个比较特殊了,创建了类Demo6,这个类继承了Demo类,并且注意Demo后面的部分<String, Integer>,这个指定了具体的类型了,此时T1的具体类型就是String类型了,T2对应的具体类型就是Integer类型了。
@2:获取Demo6对应的Class对象
@3:这行代码比较关键,这个调用了Class类中的getGenericSuperclass方法,这个方法可以获取当前类父类的具体类型信息,如果父类是泛型,则会返回泛型详细信息,泛型类型在java中用ParameterizedType接口表示,所以@3代码返回的类型一定是ParameterizedType接口类型的了。
@4:输出了genericSuperclass变量的类型,注意上面第2行输出:ParameterizedTypeImpl,这个是ParameterizedType接口的一个实现类。
@5:这个地方加了个判断,判断是不是ParameterizedType类型的,然后if内部输出了泛型类型的具体的信息,调用了ParameterizedType接口中的3个方法去获取了具体的参数类型的信息,输出中的5/6行可以看到输出了具体的类型String和Integer。
根据上面代码的原理,我们可以将下面的代码进行改造:
package com.javacode2018.chat05.demo11;
public class Demo5<T1, T2> { //@1
public void m1(Demo5<T1, T2> demo5) { //@2
System.out.println(demo5.getClass());
}
public static void main(String[] args) {
Demo5<String, Integer> demo5 = new Demo5<>();//@3
demo5.m1(demo5);
}
}
如果我们想获取Demo5的具体信息,需要给Demo5创建一个之类才可以,此处我们可以使用java中的匿名内部类来友好的解决这个问题,将上面代码变换一下,变成下面这样:
package com.javacode2018.chat05.demo11;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class Demo5<T1, T2> { //@1
public void m1(Demo5<T1, T2> demo) { //@2
//demo6Class对应的是Demo6的Class对象
Class<? extends Demo5> demoClass = demo.getClass();
//获取Demo6的父类的详细类型信息,包含泛型信息
Type genericSuperclass = demoClass.getGenericSuperclass();
// 泛型类型用ParameterizedType接口表示,输出看一下是不是这个接口类型的
System.out.println(genericSuperclass.getClass());
if (genericSuperclass instanceof ParameterizedType) {
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());
}
}
public static void main(String[] args) {
Demo5<String, Integer> demo5 = new Demo5<String, Integer>() {
};//@3
demo5.m1(demo5);
}
}
关键代码在@3,这个地方利用了一个匿名内部类,相当于创建了Demo5的一个子类,并且指定了Demo5中两个泛型变量类型的具体类型。
运行代码输出:
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class com.javacode2018.chat05.demo11.Demo5
java.lang.String
java.lang.Integer
null
这次我们获取到了泛型类中具体的类型了。
这种玩法在fastjson中有用到,再来看个案例:
package com.javacode2018.chat05.demo11;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.*;
import java.io.Serializable;
public class Demo7 {
/**
* 通用的返回值类型
* @param
*/
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Result implements Serializable { //@1
private String code;
private String subCode;
private String msg;
private T data;
}
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public static class UserModel { //@2
private Integer id;
private String name;
}
/**
* 返回一个用户信息
* @return
*/
public static Result getUser() { //@3
UserModel userModel = UserModel.builder().id(1).name(“路人甲Java”).build();
Result result = Result.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”:“路人甲Java”},“msg”:“操作成功”}
System.out.println(userString); //@5
//下面我们需要将userString反序列化为Result对象
Result userModelResult = JSON.parseObject(userString, new TypeReference<Result>() {
}); //@6
//我们来看看Result中的data是不是UserModel类型的
System.out.println(userModelResult.getData().getClass()); //@6
}
}
先看看运行结果:
{“code”:“1”,“data”:{“id”:1,“name”:“路人甲Java”},“msg”:“操作成功”}
class com.javacode2018.chat05.demo11.Demo7$UserModel
@1:创建了一个Result类型的,这个类型可以作为任何接口通用的返回值类型,这个大家可以借鉴,接口有几个通用的字段:code:状态码,subCode:子状态码,data:具体的任何类型的数据,data的具体类型可以在创建Result的时候指定,msg:接口返回的提示信息(如错误提示,操作成功等信息)。
@2:创建了一个用户类
@3:这个方法模拟返回一个用户的信息,用户信息封装在Result中。
@4:将用户信息转换为json字符串返回
@5:输出了用户信息字符串,也就是上面输出中的第一行的内容。
@6:这个是上面代码的关键,调用了fastjson中的方法,将字符串反序列化为Result,fastjson是如何获取泛型类Result中T的具体的类型的呢,T具体的类型对应的是UserModel,关键代码就是下面这行代码:
new TypeReference<Result>() {
}
这个相当于创建了一个TypeReference类的一个子类,注意TypeReference后面尖括号中的东西,是,通过这个指定了泛型变量类型的具体类型,我们去看一下TypeReference类源码,上一些关键代码:
public class TypeReference {
protected TypeReference(){
Type superClass = getClass().getGenericSuperclass(); //@1
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; //@2
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
}
注意上面的@1和@2是不是很熟悉了,fastjson中获取泛型的具体类型也是让我们采用匿名内部类去实现的,最后内部也是调用getGenericSuperclass去获取具体的泛型类型中具体的类型的。
fastjson maven配置:
com.alibaba
fastjson
1.2.62
通配符类型
通配符在java中 使用?表示,例如:? extends Number和? super Integer。
java中通配符对应的类型是WildcardType接口,可以通过这个接口来获取通配符具体的各种信息。
通配符上边界
通配符具体的类型,可以任意指定,但是我们可以限定通配符的上边界,上边界指定了这个通配符能够表示的最大的范围的类型。
比如:?extends Integer,那么?对应的具体类型只能是Integer本身或者其子类型。
通配符上边界
也可以给通配符指定下边界,下边界定义了通配符能够表示的最小的类型。
比如:? super C1,那么?对应的具体类型只能是C1类型或者C1的父类型。
package com.javacode2018.chat05.demo11;
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 Demo8 {
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 {
Method m1 = Demo8.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 parameterizedType = (ParameterizedType) genericParameterType; //@5
//下面获取Map后面两个尖括号中的泛型参数列表,对应? super C2, ? extends C1这部分的内容,这部分在java中对应WildcardType接口类型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); //@6
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) actualTypeArgument;
//获取通配符的名称,输出是?
System.out.println(“通配符类型名称:” + wildcardType.getTypeName());//@7
//获取通配符的上边界
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();
// 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.javacode2018.chat05.demo11.Demo8$C2
通配符上边界类型:java.lang.Object
通配符下边界类型:com.javacode2018.chat05.demo11.Demo8$C2
通配符类型名称:? extends com.javacode2018.chat05.demo11.Demo8$C1
通配符上边界类型:com.javacode2018.chat05.demo11.Demo8$C1
获取m1方法返回值泛型类型详细信息
通配符类型名称:?
通配符上边界类型:java.lang.Object
具体的就不解释了,只需要注意一点?通配符的信息使用WildcardType接口表示,可以通过这个接口获取通配符的详细信息。
泛型数组
什么是泛型数组?
数组中的元素为泛型,那么这个数组就是泛型类型的数组,泛型数组在java中使用GenericArrayType接口来表示,可以通过这个接口提供的方法获取泛型数组更详细的信息。
如:List list []; List list [][];
泛型数组类型的可以作为方法的参数、方法的返回值、泛型类的具体类型、字段的类型等等。
下面就以泛型字段来举例,一起来获取泛型字段的详细信息。
package com.javacode2018.chat05.demo11;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
public class Demo9 {
List list[]; //@1
public static void main(String[] args) throws NoSuchFieldException {
Field list = Demo9.class.getDeclaredField(“list”);
//获取字段的泛型类型
Type genericType = list.getGenericType(); //@2
//看看字段的具体泛型类型
System.out.println(genericType.getClass()); //@3
if (genericType instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) genericType;
//获取数组的具体类型,具体的类型就是List,这个是个泛型类型,对应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中尖括号中的参数列表
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,这个是个泛型类型,泛型类型在java中使用ParameterizedType接口表示的。
@5:调用了ParameterizedType接口中的getActualTypeArguments方法,这个方法可以获取泛型类型中具体的类型列表,就是List后面尖括号中的参数列表。
综合案例
代码如下:
package com.javacode2018.chat05.demo11;
import java.util.List;
import java.util.Map;
public class Demo10<K, V> {
Map<String, ? extends List<? extends Map<K, V>>> [][] map;
}
上面这个挺复杂的,我们一步步拆解解析一下,步骤如下:
1、Demo10<K, V>: --------> 对应java中的Class对象
2、<K, V>:定义了2个泛型变量,泛型变量对应TypeVariable接口
3、Map<String, ? extends List<? extends Map<K, V>>> [][]map:定义了一个二维泛型数组,泛型数组用GenericArrayType接口表示
4、map中的每个元素是这个是Map<String, ? extends List<? extends Map<K, V>>> []类型的,是一个一维泛型数组,泛型数组用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后面的尖括号中有2个参数,分别是String和? extends List<? extends Map<K, V>>
7、String是java中定义的类型,对应java中的Class对象
8、? extends List<? extends Map<K, V>>是通配符类型的,对应WildcardType接口,通配符指定了上边界,上边界是List<? extends Map<K, V>>
9、List<? extends Map<K, V>>又是一个泛型类型,泛型类型对应ParameterizedType接口,List<? extends Map<K, V>>的尖括号中又定义了这个泛型类型的具体的类型? extends Map<K, V>
10、? extends Map<K, V>又是一个通配符类型,对应WildcardType接口,这个通配符指定了上边界为Map<K,V>
11、Map<K,V>又对应泛型类型,泛型类型对应ParameterizedType接口,调用这个接口的getActualTypeArguments()方法获取泛型中的参数列表K和V
12、K和V是Demo10中定义的泛型变量类型,泛型变量类型对应TypeVariable接口
按照上面的思路,我们来完善一下解析代码:
package com.javacode2018.chat05.demo11;
import sun.security.util.Length;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
public class Demo10<K, V> {
Map<String, ? extends List<? extends Map<K, V>>>[][] map;
public static void parseType(Type type, int level) {
String whileString = whileString(level);
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++;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到
又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考
以下是部分内容截图
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
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++;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-UJCa6zak-1713742381806)]
[外链图片转存中…(img-V6KJa8xt-1713742381807)]
[外链图片转存中…(img-JFd9uAdN-1713742381807)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到
又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考
以下是部分内容截图
[外链图片转存中…(img-VsmV4kGO-1713742381807)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!