Java:反射+泛型:获取类型参数的实例
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
場景描述:
我需要開發(fā)四個頁面,每個頁面都是只涉及增刪改查的基本邏輯。
最簡單的寫法:
創(chuàng)建四個接口A,B,C,D,每個接口中都聲明了增刪改查四個方法,完全一致
public Map<String,Object> delete(HttpServletRequest request, User user);public Map<String,Object> query(HttpServletRequest request, User user, Map<String, Object> params);public Map<String,Object> insert(HttpServletRequest request, User user);public Map<String,Object> update(HttpServletRequest request, User user);為上面四個接口分別創(chuàng)建四個實(shí)現(xiàn)類,復(fù)寫接口中的增刪改查方法
接口A的實(shí)現(xiàn)類
@Override public Map<String, Object> delete(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "delete");return commandExecutor.execute(new DaoAImpl(request, params, user)); } @Override public Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {params = null == params ? new HashMap<String,Object>() : params;params.put("operation", "query");return commandExecutor.execute(new DaoAImpl(request, params, user)); } @Override public Map<String, Object> insert(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "insert");return commandExecutor.execute(new DaoAImpl(request, params, user)); } @Override public Map<String, Object> update(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "update");return commandExecutor.execute(new DaoAImpl(request, params, user)); }接口B的實(shí)現(xiàn)類
@Override public Map<String, Object> delete(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "delete");return commandExecutor.execute(new DaoBImpl(request, params, user)); } @Override public Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {params = null == params ? new HashMap<String,Object>() : params;params.put("operation", "query");return commandExecutor.execute(new DaoBImpl(request, params, user)); } @Override public Map<String, Object> insert(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "insert");return commandExecutor.execute(new DaoBImpl(request, params, user)); } @Override public Map<String, Object> update(HttpServletRequest request, User user) {Map<String,Object> params = new HashMap<String,Object>();params.put("operation", "update");return commandExecutor.execute(new DaoBImpl(request, params, user)); }接口C,D 的實(shí)現(xiàn)類就不在展示了。其中主要區(qū)別就是:
ServiceAImpl調(diào)用DaoAImpl的對象
ServiceBImpl調(diào)用DaoBImpl的對象
ServiceCImpl調(diào)用DaoCImpl的對象
ServiceDImpl調(diào)用DaoDImpl的對象
看完上面的代碼,你可以發(fā)現(xiàn),重復(fù)的代碼太多了,需要整理下
解決方案:
接口:可以將增刪改查的方法聲明放到一個基礎(chǔ)接口中,然后繼承這個基礎(chǔ)接口就行。
基礎(chǔ)service接口
package com.engine.odoc.service;import java.util.Map;import javax.servlet.http.HttpServletRequest;import weaver.hrm.User;public interface BaseService {public Map<String,Object> delete(HttpServletRequest request, User user);public Map<String,Object> query(HttpServletRequest request, User user, Map<String, Object> params);public Map<String,Object> insert(HttpServletRequest request, User user);public Map<String,Object> update(HttpServletRequest request, User user); }繼承基礎(chǔ)service接口的接口
package com.engine.odoc.service;public interface ServiceA extends BaseService {} package com.engine.odoc.service;public interface ServiceB extends BaseService {} package com.engine.odoc.service;public interface ServiceC extends BaseService {} package com.engine.odoc.service;public interface ServiceD extends BaseService {}接口的實(shí)現(xiàn):同樣是增刪改查四個復(fù)寫的方法,唯一不同的就是不同的實(shí)現(xiàn)類調(diào)用不同的持久層(DAO)對象。期初的想法與處理接口的想法一樣,把復(fù)寫的增刪改查方法寫到一個基礎(chǔ)service實(shí)現(xiàn)類中,然后繼承這個基礎(chǔ)service實(shí)現(xiàn)類即可。
為了能實(shí)現(xiàn)這個功能,我們需要用到Java中的泛型和反射知識
新建一個基礎(chǔ)service實(shí)現(xiàn)類
package com.engine.odoc.service.impl;public class BaseServiceImpl<T> implements BaseService {@Overridepublic Map<String, Object> delete(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {}@Overridepublic Map<String, Object> insert(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> update(HttpServletRequest request, User user) {}}可以看到這個基礎(chǔ)service實(shí)現(xiàn)類接受了一個類型參數(shù)T
那些繼承了這個基礎(chǔ)實(shí)現(xiàn)類的類,就可以通過這個類型參數(shù),把需要調(diào)用的Dao層對象的類型傳遞到父類當(dāng)中
?
?
接下來,我們需要思考的是,如何通過這個類型參數(shù)T,來得到T的一個實(shí)例。
我們先上菜
package com.engine.odoc.service.impl;import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map;import javax.servlet.http.HttpServletRequest;import com.engine.odoc.service.BaseService;public class BaseServiceImpl<T> implements BaseService {public Class cusClass;public BaseServiceImpl() {// 獲取T.classType genericSuperclass = this.getClass().getGenericSuperclass();if(genericSuperclass instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;Type[] typeArray = parameterizedType.getActualTypeArguments();if(null != typeArray && typeArray.length>0) {cusClass = (Class) typeArray[0];}}}/*** 獲取T類的實(shí)例* @param request* @param params* @param user* @return*/private T getTInstance(HttpServletRequest request, Map<String,Object> params, User user) {try {return (T) cusClass.getConstructor(new Class[]{HttpServletRequest.class, Map.class, User.class}).newInstance(request, params, user);} catch (Exception e) {e.printStackTrace();}return null;}@Overridepublic Map<String, Object> delete(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> query(HttpServletRequest request, User user, Map<String, Object> params) {}@Overridepublic Map<String, Object> insert(HttpServletRequest request, User user) {}@Overridepublic Map<String, Object> update(HttpServletRequest request, User user) {}}?
????????我們可以看到,我們在這個基礎(chǔ)service實(shí)現(xiàn)類的默認(rèn)構(gòu)造函數(shù)中確認(rèn)了類型參數(shù)T的類型,得到T.class。之后在getTInstance() 方法中通過反射的方式獲取了T的實(shí)例。
?
Type genericSuperclass = this.getClass().getGenericSuperclass();????????這行代碼我們是寫在父類(BaseServiceImpl)的默認(rèn)構(gòu)造函數(shù)中的。繼承這個類的子類們,在執(zhí)行默認(rèn)構(gòu)造函數(shù)的時候,會先執(zhí)行super();調(diào)用父類的默認(rèn)構(gòu)造函數(shù),這時候,以上這行代碼中的this就代表了子類,調(diào)用getGenericSuperclass()來獲得父類(BaseServiceImpl),而得到的父類(BaseServiceImpl)可能是BaseServiceImpl<DaoAImpl>,BaseServiceImpl<DaoBImpl>... ,也可能BaseServiceImpl<T>。
我們可以使用接口ParameterizedType,用來檢驗(yàn)類型參數(shù)是否被參數(shù)化
Type genericSuperclass = this.getClass().getGenericSuperclass(); if(genericSuperclass instanceof ParameterizedType) {// 該泛型類的類型參數(shù)已經(jīng)被參數(shù)化 }如果類型參數(shù)已經(jīng)被參數(shù)化,我們就可以通過調(diào)用下面的方法
package java.lang.reflect;public interface ParameterizedType extends Type {Type[] getActualTypeArguments(); }返回的數(shù)組中就存儲了類型參數(shù)T的具體類型,即T.class
?
獲取到T.class之后,我們就可以通過反射來進(jìn)一步獲得T的實(shí)例
try {return (T) cusClass.getConstructor(new Class[]{HttpServletRequest.class, Map.class, User.class}).newInstance(request, params, user); } catch (Exception e) {e.printStackTrace(); }?
?
?
?
轉(zhuǎn)載于:https://my.oschina.net/u/3229807/blog/1821207
總結(jié)
以上是生活随笔為你收集整理的Java:反射+泛型:获取类型参数的实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博弈论中的囚徒困境
- 下一篇: 【Java爬虫】爬取淘宝买家秀