泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

输出中可以看到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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
架构面试专题及架构学习笔记导图.png
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
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获取)

img

最后

码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到

又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考

以下是部分内容截图
[外链图片转存中…(img-VsmV4kGO-1713742381807)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值