模擬一個場景:html
衆所周知,EasyExcel導出Excel文檔是依賴於註解完成的,在實體類須要導出的屬性上面加上註解,導出的時候會自動識別該屬性。java
假如咱們如今須要導出用戶的信息,又不想污染本來的實體類,又要過濾掉password這個屬性。那麼咱們能夠另外建立一個實體類,不包含password屬性。而後咱們將查到的用戶信息,賦值給新建立的對象便可。程序員
賦值這一步是比較繁瑣的,咱們須要寫循環,而後判斷,而後賦值。等未來須要導出管理員信息的時候咱們又要寫循環,而後判斷,而後賦值、、、數據庫
怎麼能寫一個共用的方法去幫咱們作循環、判斷、賦值這些事呢?源對象類型不肯定,目標對象類型不肯定。工具
因而,反射機制來了。它來了,它來了,它哼着小曲走來了、、、測試
經過 Java 的反射機制,程序員能夠更深刻地控制程序的運行過程。例如,在程序運行時由用戶輸入一個類名,而後動態獲取該類擁有的構造、屬性和方法,甚至調用任意類的任意方法。
google
Java 反射機制主要提供瞭如下功能,這些功能都位於 java.lang.reflect包下。spa
在運行時判斷任意一個對象所屬的類。.net
在運行時構造任意一個類的對象。代理
在運行時判斷任意一個類所具備的成員變量和方法。
在運行時調用任意一個對象的方法。
生成動態代理。
請參照: 基於SpringBoot構建分模塊項目
UserOne爲與數據庫表對應的實體類,UserTwo爲即將要經過EasyExcel導出的對象
package com.wayne.common.entity; /** * @author Wayne * @date 2019/6/5 */ public class UserOne { private Integer id; private String username; private String password; // Getter and Setter 、、、 }
package com.wayne.common.dto; /** * @author Wayne * @date 2019/6/5 */ public class UserTwo { private Integer id; private String username; // Getter and Setter 、、、 }
經過反射建立對象、調用方法
package com.wayne.common.utils; import com.google.common.collect.Lists; import com.wayne.common.exception.CopyPropertyException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; /** * @author Wayne * @date 2019/6/5 */ public class BaseUtil { /** * 將一個集合中對象的值拷貝到另外一個對象,屬性相同即賦值 * @param source 源數據,將此對象數據取出 * @param tClass 目標對象,將取出的數據賦值到該對象中 * @param <T> 源數據類型 * @param <E> 目標數據類型 * @return 被賦值後的目標對象集合 * @throws CopyPropertyException 自定義異常,經過反射建立對象或調用方法時拋出的異常 */ public static <T, E> List<E> copyProperties(List<T> source, Class<E> tClass) throws CopyPropertyException { // 判斷傳入源數據是否爲空,若是空,則拋自定義異常 if(null == source) { throw new CopyPropertyException("數據源爲空"); } // 建立一個集合,用於存儲目標對象,所有數據抓換完成後,將該集合返回 List<E> targetList = Lists.newArrayList(); // 循環取到單個源對象 for(T t : source) { // 獲取源對象的類的詳情信息 Class<?> sClass = t.getClass(); // 獲取源對象的全部屬性 Field[] sFields = sClass.getDeclaredFields(); // 獲取目標對象的全部屬性 Field[] tFields = tClass.getDeclaredFields(); E target; try { // 經過類的詳情信息,建立目標對象 這一步等同於UserTwo target = new UserTwo(); target = tClass.newInstance(); } catch (Exception e) { e.printStackTrace(); throw new CopyPropertyException("目標對象建立失敗"); } // 循環取到源對象的單個屬性 for(Field sField : sFields) { // 循環取到目標對象的單個屬性 for(Field tField : tFields) { // 判斷源對象的屬性名、屬性類型是否和目標對象的屬性名、屬性類型一致 if(sField.getName().equals(tField.getName()) && sField.getGenericType().equals(tField.getGenericType())) { try { // 獲取源對象的屬性名,將屬性名首字母大寫,拼接如:getUsername、getId的字符串 String sName = sField.getName(); char[] sChars = sName.toCharArray(); sChars[0] -= 32; String sMethodName = "get" + String.valueOf(sChars); // 得到屬性的get方法 Method sMethod = sClass.getMethod(sMethodName); // 調用get方法 Object sFieldValue = sMethod.invoke(t); // 獲取目標對象的屬性名,將屬性名首字母大寫,拼接如:setUsername、setId的字符串 String tName = tField.getName(); char[] tChars = tName.toCharArray(); tChars[0] -= 32; String tMethodName = "set" + String.valueOf(tChars); // 得到屬性的set方法 Method tMethod = tClass.getMethod(tMethodName, tField.getType()); // 調用方法,並將源對象get方法返回值做爲參數傳入 tMethod.invoke(target, sFieldValue); break; } catch (Exception e) { e.printStackTrace(); throw new CopyPropertyException("轉換失敗,請檢查屬性類型是否匹配"); } } } } // 將經過反射建立的目標對象放入集合中 targetList.add(target); } // 返回集合 return targetList; } }
開發怎能不留擴展字段 (¬_¬)…