0%

Type接口

Type接口

[TOC]

一、介绍

Type接口是Java中所有类型的公共高级接口,是由JDK5引入,主要是为了实现参数化类型(泛型),Class类是该接口的直接实现类。

​ 在日常开发过程中,一些公共抽象点需要使用泛型进行结构抽象,从而达到业务调用点灵活调用的目的。之前有一次由于不懂Type接口以及子类,导致部分抽象做的不够灵活,本篇主要记录Type接口下参数化类型ParameterizedType的一些API使用。

二、子接口

3LURqsICMOANz7e

从左到右依次是直接实现类Class,数组类型接口GenericArrayType,参数化类型接口ParameterizedType,通配符表达式接口WildcardType,类型变量接口(泛指任何类)TypeVariable。大概知道了几个接口之间的关系之后,直接进入一个应用场景。

​ 服务端与客户端交互是设计了一个数据固定的数据结构,其中该数据结构中的存在两个属性String dataJsonT Data,而客户端只会传输经过一定的编码或者加密处理dataJson字段,由服务端自行处理字符串数据。最理想的情况就是,服务端做一层统一处理,接收到该实体对象之后,根据服务端和客户端之间的约定,解析其中的dataJson为对应的data数据。前面有一篇专门来说这个参数解析这里。当时同事最开始提出这个问题的时候还并没有提出想将json转为实体,仅想通过某种统一处理,将json解码(客户端传输过来的是经过某种编码)。最终选择的方案是通过RequestBodyAdvice,当完成解码这个动作之后,同事发现,既然都通过统一处理json串解码了,那不就可以通过泛型的方式把json转换为对应的实体?我原本以为获取不到对应类的泛型,而恰巧(真的是巧)。RequestBodyAdvice#afterBodyRead方法上参数是Type类型,从而能通过它(如果是泛型则类型为ParameterizedType)就可以获取到对应类的泛型类型,从而进行转换为对应的实体。

1
2
3
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, 
MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType)

这里我想抛出我的问题:如果这里没有Type参数,可以看之前那篇文章的其他两种方式,比如现在的场景就是使用@InitBuilder的方式最合适,要怎么获取到Type,或者说获取到参数的ParameterizedType

度娘了一下,对查到的一些写法的分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 直接Class: 这种写法纯属骗人,从类图可以看出,就算用父接口引用,其实本质上还是Class类型
// 和ParameterizedType类型不符。
DataEntity<User> dataEntity = new DataEntity<User>();
Type t = (Type)dataEntity.getClass();

// 2. 通过class.getGenericSuperclass():这种方式可以获取到的的确是ParameterizedType,
// 但那是父类的ParameterizedType(如果父类是泛型的情况)。
// 那么如果A继承B,B能获取到A的class, 再通过A的class获取到B的泛型参数, 虽然有点绕, 但也不失为一种方式。
List<String> list = new ArrayList<String>();
Type type =list.getClass().getGenericSuperclass();

// 3.通过反射获取: 反射是根据类来获取对应的属性,这种方式下获取的是泛型前的类型TypeVariable
// 如果某个方法中的参数是泛型类型, 通过method.getGenericParameterTypes()可以获取到ParameterizedType
DataEntity<User> dataEntity = new DataEntity<User>();
try{
Field field = dataEntity.getClass().getField("data");
Type paraType = field.getGenericType();
System.out.println(paraType);
}catch(Exception e){
e.printStackTrace();
}

根据以上的3种方法,1和3直接就不对。只有2沾点边。所以在设计上可以将A设计为泛型接口,B作为A的具体实现,这时就可以获取到对应的泛型类型。

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
@Test
public void testAA(){
B b = new B();
Type[] type = b.getClass().getGenericInterfaces();
System.out.println(((ParameterizedType)type[0]).getActualTypeArguments()[0]);
}


interface A<T>{

T getData();

void setData(T data);
}

class B implements A<User>{

@Override
public User getData() {
return null;
}

@Override
public void setData(User data) {
}
}

三、常用API

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
/**
* 这里要时刻注意获取的父类的的Type或者是Class。

* class.getSuperclass() 返回直接继承的父类(类型擦除, 不显示泛型参数)
* class.getGenericSuperclass() 返回直接继承的父类(包含泛型参数)
*
* class.getInterfaces() 返回直接实现的接口
* class.getGenericInterface() 返回直接实现的接口(包含泛型参数)

* ParameterizedType:
* getActualTypeArguments() 返回参数化类型列表(比如DataEntity<User>, 通过该方法获取到的就是User)
* getOwnerType() 返回这个ParameterizedType所在类的Type
* 比如Map<String, Object>的getOwnerType=null,Map.Entry<String,String>的getOwnerType=Map)
* getRawType() 表示声明此类型的类或者接口

* @Author: xiaocainiaoya
* @Date: 2021/06/22 22:39:26
**/
@Test
public void test4(){
List<String> list = new ArrayList<String>();
Type type =list.getClass().getGenericSuperclass();
System.out.println(list.getClass().getGenericSuperclass());
System.out.println(list.getClass().getSuperclass());

Class<?>[] classes = list.getClass().getInterfaces();
Type[] types = list.getClass().getGenericInterfaces();

System.out.println(list.getClass().getInterfaces());
System.out.println(list.getClass().getGenericInterfaces());
}

/**
* ParameterizedType:
* getActualTypeArguments() 返回参数化类型列表(比如DataEntity<User>, 通过该方法获取到的就是User)
* getOwnerType() 返回这个ParameterizedType所在类的Type(一般来说是空的)
* 比如Map<String, Object>的getOwnerType=null,Map.Entry<String,String>的getOwnerType=Map)
* getRawType() 表示声明此类型的类或者接口
*
* @Author: xiaocainiaoya
* @Date: 2021/06/22 23:16:26
* @param
* @return:
**/
@Test
public void test2(){
try{
Method method = TypeTest.class.getMethod("test", Map.Entry.class,
List.class, DataEntity.class);
Type[] types = method.getGenericParameterTypes();
for (Type type : types) {
ParameterizedType parameterizedType = (ParameterizedType) type;
System.out.println(parameterizedType.getOwnerType() + " || " +
parameterizedType.getRawType() + " || " +
Arrays.toString(parameterizedType.getActualTypeArguments()));
}
}catch(Exception e){
e.printStackTrace();
}
}

//interface java.util.Map || interface java.util.Map$Entry || [class cn.com.xiaocainiaoya.entity.User, class java.lang.String]
//null || interface java.util.List || [class cn.com.xiaocainiaoya.entity.User]
//null || class cn.com.xiaocainiaoya.entity.DataEntity || [class //cn.com.xiaocainiaoya.entity.User]

public static <T, U> void test(Map.Entry<User, String> mapEntry, List<User> list, DataEntity<User> userDataEntity) {}

-------------本文结束感谢您的阅读-------------