Java反射--基于ParameterizedType实现泛型类,参数化类型

一、引子:

项目中使用Gson的反序列化将json转化成具体的对象,具体方法是:

package com.google.gson;下的反序列化方法

1 public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException{
2   ......
3 }

参数<T> :the type of the desired object

参数json:要被反序列化的json数据;

参数typeOfT:指定的通用类型的src。可以通过 Type typeOfT = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();获得;

边对象:使用了泛型类

 

1 public class CtiEdgeT<T,V> {
2     private String id;
3     //顶点
4     private T inVertex;
5     //对应点
6     private V outVertex;
7    ......
8 }

 

 

 

最开始考虑使用具体的model作为参数,例如CtiEdgeT<DomainVertex,IpVertex> 具体类型(DomainVertex,IpVertex)做为参数,通过gson反序列化获得具体类型的CtiEdgeT<SampleVertex,IpVertex>对象,例如:

 1  private boolean saveEdgeToGraph(String msg, String inType, String outType) {
 2         boolean flag = false;
 3         switch (inType){
 4             case Constant.SAMPLE_LABEL:{
 5                 switch (outType){
 6                     case Constant.IP_LABEL:{
 7                         Type type = new TypeToken<CtiEdgeT<SampleVertex,IpVertex>>() {
 8                         }.getType();
 9                         CtiEdgeT<SampleVertex,IpVertex> edge =  JsonUtil.getJson().fromJson(msg, type);
10                         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);                     
11                         break;
12                     }
13                     case Constant.DOMAIN_LABEL:{
14                         Type type = new TypeToken<CtiEdgeT<SampleVertex,DomainVertex>>() {
15                         }.getType();
16                         CtiEdgeT<SampleVertex,DomainVertex> edge =  JsonUtil.getJson().fromJson(msg, type);
17                         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);                        
18                         break;
19                     }
20                     。。。。。。
21                 }
22             }
23         }
24     }

 

本项目中就有20+种数据,即20+个model,这样做导致的结果就是如果有很多不同的边CtiEdgeT<T,V>,将会写大量的冗余代码。

二、解决方案:

可以通过 ParameterizedType 这个接口实现泛型类,参数化类型,参考这篇文章: https://www.jianshu.com/p/b1ad2f1d3e3e

具体实现如下:

 

EdgeParameterTypeImpl:
 1 import java.lang.reflect.ParameterizedType;
 2 import java.lang.reflect.Type;
 3 
 4 public class EdgeParameterTypeImpl implements ParameterizedType {
 5 
 6     //
 7     private Class ctiEdgeT ;
 8     //顶点
 9     private Class inVertex ;
10     //对应点
11     private Class outVertex ;
12     
13     public EdgeParameterTypeImpl(Class ctiEdgeT,Class inVertex,Class outVertex) {
14         this.ctiEdgeT = ctiEdgeT ;
15         this.inVertex = inVertex ;
16         this.outVertex = outVertex ;
17     }
18     
19     @Override
20     public Type[] getActualTypeArguments() {
21         return new Type[]{inVertex,outVertex};
22     }
23 
24     @Override
25     public Type getRawType() {
26         return ctiEdgeT;
27     }
28 
29     @Override
30     public Type getOwnerType() {
31         return null;
32     }
33   
34 }
 边 CtiEdgeT<T,V>:

 

 1 public class CtiEdgeT<T,V> {
 2     private String id;
 3     //顶点
 4     private T inVertex;
 5     //对应点
 6     private V outVertex;
 7 
 8     public String getId() {
 9         return id;
10     }
11 
12     public void setId(String id) {
13         this.id = id;
14     }
15 
16     public T getInVertex() {
17         return inVertex;
18     }
19 
20     public void setInVertex(T inVertex) {
21         this.inVertex = inVertex;
22     }
23 
24     public V getOutVertex() {
25         return outVertex;
26     }
27 
28     public void setOutVertex(V outVertex) {
29         this.outVertex = outVertex;
30     }
31 }

 

通过参数化泛型解决,传入的具体model类作为参数,反序列化得到具体的边

 1 private boolean saveEdgeToGraph(String msg, String inType, String outType) {
 2         boolean flag = false;
 3         Class<?> inVertex = Constant.vertexClassMap.get(inType); //inType : SAMPLE_LABEL
 4         Class<?> outVertex = Constant.vertexClassMap.get(outType); //outType : IP_LABEL
 5         EdgeParameterTypeImpl type = new EdgeParameterTypeImpl(CtiEdgeT.class, inVertex, outVertex);
 6         @SuppressWarnings("rawtypes")
 7         CtiEdgeT edge =  JsonUtil.getJson().fromJson(msg,type);
 8         flag = this.doSaveEdgeToGraph(inType,outType,edge.getInVertex(),edge.getOutVertex(),edge);       
 9         return flag;
10     }

从vertexClassMap中取对应的具体model
 1 public class Constant {
 2     @SuppressWarnings("rawtypes")
 3     public static Map<String,Class> vertexClassMap = new HashMap<String,Class>();
 4     
 5     static{
 6         try {
 7             vertexClassMap.put(SAMPLE_LABEL,SampleVertex.class);
 8             vertexClassMap.put(IP_LABEL,IpVertex.class);
 9             vertexClassMap.put(DOMAIN_LABEL,DomainVertex.class);
10             。。。。。。
11             }
12         }
13     }    

 

通过追踪代码:CtiEdgeT edge = JsonUtil.getJson().fromJson(msg,type);可以发现type的源码

1   TypeToken(Type type) {
2     this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
3     this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
4     this.hashCode = this.type.hashCode();
5   }

 

 1   public static Type canonicalize(Type type) {
 2     if (type instanceof Class) {
 3       Class<?> c = (Class<?>) type;
 4       return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
 5 
 6     } else if (type instanceof ParameterizedType) {
 7       ParameterizedType p = (ParameterizedType) type;
 8       return new ParameterizedTypeImpl(p.getOwnerType(),
 9           p.getRawType(), p.getActualTypeArguments());
10 
11     }
12     ......
13   }

上面标红的代码会执行具体model的实现类的方法,得到具体的类型。

三、拓展点:

关于ParameterizedType 的解析可以 参考这篇文章: https://blog.csdn.net/a327369238/article/details/52622331

 

 1 public class ParameterTest {
 2     public static void main(String[] args) {
 3         Method method = null;
 4         try {
 5             //这里的第二个参数,和getRawType()意义类似
 6             method = new ParameterTest().getClass().getMethod("test", HashMap.class);
 7         } catch (NoSuchMethodException e) {
 8             e.printStackTrace();
 9         }
10         Type[] types = method.getGenericParameterTypes();
11         ParameterizedType ptype = (ParameterizedType) types[0];
12         Type rawType = ptype.getRawType();
13         System.out.println("最外层<>前面那个类型 rawType:"+rawType);
14         Type type = ptype.getActualTypeArguments()[0];
15         Type type1 = ptype.getActualTypeArguments()[1];
16         System.out.println("泛型 type:"+type);
17         System.out.println("泛型 type1:"+type1);
18         Type ownerType = ptype.getOwnerType();
19         System.out.println("ownerType:"+ownerType);
20         //type是Type类型,但直接输出的不是具体Type的五种子类型,
21        //而是这五种子类型以及WildcardType具体表现形式
22         System.out.println("泛型 type name:"+type.getClass().getName());
23     }
24     public void test(HashMap<String,Integer> a){
25     }
26 }

 结果:

1 最外层<>前面那个类型 rawType:class java.util.HashMap
2 泛型 type:class java.lang.String
3 泛型 type1:class java.lang.Integer
4 ownerType:null
5 泛型 type name:java.lang.Class

 因此 EdgeParameterTypeImpl 中的

 public Type getRawType() {   return ctiEdgeT;} 得到 边ctiEdgeT,而边 CtiEdgeT<T,V> 是参数是泛型,

 public Type[] getActualTypeArguments() { return new Type[]{inVertex,outVertex};} 得到 参数 inVertex,outVertex

----------------------------------------------多做多解决多总结-----------------------------------

 

posted @ 2018-09-26 16:52  java白丁  阅读(2973)  评论(0编辑  收藏  举报