模拟一个场景: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; } }
开发怎能不留扩展字段 (¬_¬)…