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

----------------------------------------------多做多解決多總結-----------------------------------

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM