Java反射機制調用對象的方法 —— 將一個對象的屬性值賦值給另外一個對象的屬性

 

模擬一個場景:html

衆所周知,EasyExcel導出Excel文檔是依賴於註解完成的,在實體類須要導出的屬性上面加上註解,導出的時候會自動識別該屬性。java

假如咱們如今須要導出用戶的信息,又不想污染本來的實體類,又要過濾掉password這個屬性。那麼咱們能夠另外建立一個實體類,不包含password屬性。而後咱們將查到的用戶信息,賦值給新建立的對象便可。程序員

賦值這一步是比較繁瑣的,咱們須要寫循環,而後判斷,而後賦值。等未來須要導出管理員信息的時候咱們又要寫循環,而後判斷,而後賦值、、、數據庫

怎麼能寫一個共用的方法去幫咱們作循環、判斷、賦值這些事呢?源對象類型不肯定,目標對象類型不肯定。工具

因而,反射機制來了。它來了,它來了,它哼着小曲走來了、、、測試

經過 Java 的反射機制,程序員能夠更深刻地控制程序的運行過程。例如,在程序運行時由用戶輸入一個類名,而後動態獲取該類擁有的構造、屬性和方法,甚至調用任意類的任意方法。google

Java 反射機制主要提供瞭如下功能,這些功能都位於 java.lang.reflect包下。spa

  • 在運行時判斷任意一個對象所屬的類。.net

  • 在運行時構造任意一個類的對象。代理

  • 在運行時判斷任意一個類所具備的成員變量和方法。

  • 在運行時調用任意一個對象的方法。

  • 生成動態代理。

開發環境

請參照: 基於SpringBoot構建分模塊項目

建立對象UserOne、UserTwo

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;
    }
}

 

測試結果

預留佔位

開發怎能不留擴展字段 (¬_¬)…

相關文章
相關標籤/搜索