在实际的工作中,有时可能存在2个java bean属性之间的拷贝,而如果使用bean 之间setter方法进行设置,那么将会存在大量的冗余的代码,因此可以考虑使用反射来进行属性的拷贝操作。
大致思路如下:
1、从class文件中,获取到所有的public类型的方法
2、获取到所有的getter方法和setter方法,getter方法的获取需要考虑到boolean类型这个比较特殊的类型的获取。
3、进行属性的拷贝的时候,需要考虑到源对象中的属性值为null,是否应该拷贝到目标对象中
4、一个class文件中的getter和setter方法一般都是不可变的,因此需要进行缓存起来,避免每次都进行获取。
一、编写BeanUtils工具类,实现拷贝
/** * bean 之间的属性的复制. * * @描述 * @作者 huan * @时间 2017年11月4日 - 上午11:25:26 */ public final class BeanUtils { private static final ConcurrentHashMap<Class<?>, List<Method>> CACHE_CLASS_GET_METHOD = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Class<?>, List<Method>> CACHE_CLASS_SET_METHOD = new ConcurrentHashMap<>(); private BeanUtils() { } /** * 将src java bean的属性拷贝到 tar java bean的属性中,默认不拷贝src对象中的空对象的值. * * @param src * 源对象 * @param tar * 目标对象 */ public static void copyProperties(Object src, Object tar) { copyProperties(src, tar, true); } /** * 将src java bean的属性拷贝到 tar java bean的属性中 * * @param src * 源对象 * @param tar * 目标对象 * @param skipEmpty * 如果src中属性的值时null,是否跳过这个拷贝, true:跳过 false:不跳过 */ public static void copyProperties(Object src, Object tar, boolean skipEmpty) { List<Method> getterMethods = getGetMethod(src.getClass()); List<Method> setterMethods = getSetMethod(tar.getClass()); try { for (Method getMethod : getterMethods) { Object value = getMethod.invoke(src); if (skipEmpty && value == null) { continue; } Method method = setterMethods.stream().filter(m -> Objects.equals(m.getName(), getInvokedSetterMethodName(getMethod.getName()))).findFirst().orElse(null); if (null != method) { method.invoke(tar, value); } } } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("bean复制属性过程中产生异常", e); } } /** * 根据getter的方法名拿到setter的方法名 * * @param getterMethodName * getter的方法名 * @return setter的方法名 */ public static String getInvokedSetterMethodName(String getterMethodName) { if (getterMethodName.startsWith("get")) { return "set" + getterMethodName.substring(3); } else { return "set" + getterMethodName.substring(2); } } /** * 获取clazz中的所有public getter 方法 * * @param clazz * 需要获取getter方法的类 * @return public getter方法 */ public static List<Method> getGetMethod(Class<?> clazz) { Class<?> lockClazz = clazz; if (!CACHE_CLASS_GET_METHOD.containsKey(clazz)) { synchronized (lockClazz) { if (!CACHE_CLASS_GET_METHOD.containsKey(clazz)) { CACHE_CLASS_GET_METHOD.put(clazz, Arrays.stream(getMethods(clazz)).filter(BeanUtils::isGetterMethod).filter(m -> !Objects.equals(m.getName(), "getClass")).collect(Collectors.toList())); } } } return CACHE_CLASS_GET_METHOD.get(clazz); } /** * 获取clazz中的所有public setter 方法 * * @param clazz * 需要获取setter方法的类 * @return public setter方法 */ public static List<Method> getSetMethod(Class<?> clazz) { Class<?> lockClazz = clazz; if (!CACHE_CLASS_SET_METHOD.containsKey(clazz)) { synchronized (lockClazz) { if (!CACHE_CLASS_SET_METHOD.containsKey(clazz)) { CACHE_CLASS_SET_METHOD.put(clazz, Arrays.stream(getMethods(clazz)).filter(BeanUtils::isSetterMethod).collect(Collectors.toList())); } } } return CACHE_CLASS_SET_METHOD.get(clazz); } /** * 获取一个类中中的所有的方法 * * @param clazz * @return */ public static Method[] getMethods(Class<?> clazz) { return clazz.getMethods(); } /** * 判断一个方式是否是getter方法 * * @param method * 需要判断的方法 * @return true:是getter方法 false:不是getter方法 */ public static boolean isGetterMethod(Method method) { if (method.getName().startsWith("get") && method.getParameterCount() == 0 && method.getReturnType() != Void.class) { return true; } else if (method.getName().startsWith("is") && method.getParameterCount() == 0 && (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class))) { return true; } return false; } /** * 判断是否是setter方法 * * @param method * 需要判断的方法 * @return true是setter方法 false不是setter方法 */ public static boolean isSetterMethod(Method method) { boolean isSetter = false; if (method.getName().startsWith("set") && method.getParameterCount() == 1 && method.getReturnType() != Void.class) { isSetter = true; } return isSetter; } }
二、测试
1、编写一个实体类 SysResource
/** * 资源实体类 * * @描述 * @作者 huan * @时间 2017年11月4日 - 上午11:26:46 */ @Data public class SysResource { private String id; private String pid; private String name; private String url; private Integer type; private Date createTime; }
2、编写测试代码
相关推荐
对象属性值的复制工具类 1.全复制 2.部分复制 3.部分不复制
实现了两个对象之间属性值的拷贝,只要具有相同的属性名就可以拷贝,还有两个file对象的拷贝,实现文件的复制功能
对象属性值映射/拷贝工具。不需要创建映射规则,不要求对象类型一致,适用于简单直接的拷贝操作,可以全属性拷贝,指定属性拷贝,排除指定的属性。拷贝包含 10 个属性的对象 10 万次,耗时 4.x 秒(普通开发机)。
C#基于表达式(Expression)实现对象深拷贝,包含了核心类及示例数据。这是一个比较简单的帮助类,可作学习参考
Student student=new Student(); (Student2)student //在这个表达式(记得光标在表达式里面哦)按下alt+Enter,选中“哟嚯。。。好爽啊”就能自动生成下面代码 Student2 student2=new Student2();...
NULL 博文链接:https://bdk82924.iteye.com/blog/474092
BeanUtil属性拷贝工具类,支持基本的javabean属性拷贝,通过java反射和泛型编程实现了list属性拷贝
QT开发基于QT开发的文件拷贝工具.zipQT开发基于QT开发的文件拷贝工具.zipQT开发基于QT开发的文件拷贝工具.zipQT开发基于QT开发的文件拷贝工具.zipQT开发基于QT开发的文件拷贝工具.zipQT开发基于QT开发的文件拷贝工具...
C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数 C++类对象的拷贝构造函数
分享一个使用反射+缓存+委托,实现一个不同对象之间同名同类型属性值的快速拷贝 的小程序, http://blog.csdn.net/bluedoctor/article/details/8424510 是原理说明,相信请看链接文章。
基于c++的多线程拷贝技术。基于c++的多线程拷贝技术,包括实现流程和源代码程序。基于c++的多线程拷贝技术。
基于网络处理器的零拷贝技术,做Linux网络方面可以看看
对象属性值映射/拷贝工具。不需要创建映射规则,不要求对象类型一致,适用于简单直接的拷贝操作,可以全属性拷贝,指定属性拷贝,排除指定的属性。拷贝包含 10 个属性的对象 10 万次,耗时 4.x 秒(普通开发机)。 ...
用于两个domain对象的拷贝,支持字段自动覆盖,选择性覆盖,选择性字段拷贝,作用:当你有多个domain对象都需要生成另外的同一个domain对象的时候这个方法就很有用了,或许存在BUG,欢迎指出
一种基于高通量测序的拷贝数变异检测自动化分析解读及报告系统.pdf
(抱歉,我无法修改下载积分,本想着免积分的)C#浅拷贝(MemberwiseClone等多种方法)与深拷贝(反射、多种反序列化)实例
Omu.ValueInjecter.dll 更多信息请移步http://valueinjecter.codeplex.com/
一、List对象中的T是值类型的情况(int 类型等)...1、对于引用类型的List无法用以上方法进行复制,只会复制List中对象的引用,可以用以下扩展方法复制: static class Extensions { public static IList<T> Clone(t
对多维数组,对象,进行去重,相同的值只保留一个,常见的new Set()和filter,只能去重一维数组,并不能进行深层的去重,逻辑:判断是否为对象,为对象判断是否为数组或是真的对象,递归一直筛选为值,判断首次...
3、无论是声明NSString还是NSMutableString类型的属性时,我们希望此属性被赋值为NSMutableString类型的字符串后,此属性不会因这个可变类型字符串的改变而改变(这也是多数情况下的用法),那就用copy修饰属性