在实际的工作中,有时可能存在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、编写测试代码
相关推荐
在C#编程中,对象的深拷贝是一个重要的概念,特别是在处理复杂的数据结构时,我们需要确保复制的对象与原对象在内存中是独立的,修改其中一个不会影响另一个。本主题将详细探讨如何使用C#的表达式(Expression)来...
如何使用Java反射机制进行对象属性拷贝。 如何利用Jackson库实现复杂类型的对象转换。 不同转换方式的适用场景及其优劣。 批量对象转换的方法和实践。 阅读建议:在学习过程中,建议读者结合实际项目需求,尝试使用...
传统的对象属性拷贝方式如 `BeanUtils.copyProperties` 虽然简单易用,但存在一些问题: 1. **性能问题**:基于反射的拷贝方式相对较慢。 2. **灵活性不足**:对于同名字段无法进行特殊处理,这可能导致某些不希望...
总的来说,Apache BeanUtils库的`copyProperties`方法是Java开发中一个实用的工具,它可以显著提高代码的可读性和简洁性,尤其在处理JavaBean对象属性拷贝时。然而,理解它的内在工作原理和潜在限制同样非常重要,...
5. 实现通用操作:反射可以用来实现一些通用的功能,例如序列化/反序列化、属性拷贝等。 标签“例子程序”暗示这个压缩包可能包含以下示例: 1. 基本反射操作:展示如何获取类信息、构造器、方法和字段。 2. 动态...
标题中的"common(bean_之音属性复制).zip"提到了一个关于Java Bean属性复制的主题,这通常指的是对象间的属性拷贝或者映射过程。在Java开发中,特别是Spring框架中,Bean的属性复制是一个常见操作,它有助于减少...
5. 深拷贝与浅拷贝:这种方法仅进行浅拷贝,即引用类型属性的值只是指向了同一个对象。如果需要深拷贝(即复制对象的所有嵌套对象),则需要更复杂的逻辑。 6. 自定义逻辑:如果属性赋值需要特定的逻辑,例如验证、...
在Java编程世界中,BeanUtils.jar是一个极为重要的工具包,尤其在处理对象属性操作时,它的存在极大地简化了开发工作。BeanUtils是Apache Commons项目的一部分,提供了丰富的功能,用于方便地操作JavaBeans。本文将...
在实际开发中,我们常常需要根据对象的属性来比较,所以会重写`equals()`方法,实现基于对象内容的比较。 3. `hashCode()`方法:`hashCode()`方法返回对象的哈希码,用于哈希表(如`HashMap`和`HashSet`)的操作。`...
- **核心功能**:属性拷贝、属性访问(通过反射机制)、转换器(Converter)支持,用于在不同数据类型之间转换属性值。 - **使用示例**:`BeanUtils.copyProperties(sourceBean, targetBean)`可以将源对象的所有...
它使用反射机制实现,通过getter和setter方法进行属性的读写。其优点在于简单易用,但缺点是在大量复制操作时性能较低,因为每次复制都需要进行反射调用。 PropertyUtils是Apache Commons BeanUtils的扩展,它增强...
BeanUtil框架是一个在Java开发中常用的工具库,主要用于对象属性的获取、设置、拷贝以及类型转换等操作。它的设计目标是简化Java Bean的操作,提高代码的可读性和可维护性。这个“BeanUtil框架完整包”包含了...
在Java开发中,BeanUtils库极大地提高了开发效率,尤其是在处理对象属性的设置、获取以及复制等方面。以下是对Apache BeanUtils核心功能的详细介绍: 1. 属性自动封装与解封: BeanUtils库的主要功能之一就是自动将...
因此,开发手册建议避免使用Apache BeanUtils,转而采用更安全、性能更好的工具进行对象属性的复制。 至于日期格式化时使用'y'而不是'Y',这是因为'y'代表年的历元年(例如公历年),而'Y'代表周年的年份(基于星期...
1. **属性拷贝**:BeanUtils.copyProperties()方法可以实现两个JavaBean对象之间的属性值拷贝,极大地减少了代码量。 2. **动态属性访问**:通过BeanUtils.getProperty()和BeanUtils.setProperty(),我们可以动态地...
KVC是Runtime提供的一种间接访问对象属性的方式,无需知道属性的setter和getter。KVO则允许我们监听某个属性的变化,当属性值改变时,会自动触发观察者的方法。两者都依赖于Runtime的底层实现。 6. **Category和...
对于源码分析,Dozer 的实现基于反射和泛型,这使得它能够处理各种类型的对象。它的性能在大多数情况下是可接受的,但如果映射操作非常频繁,可能需要考虑优化,例如通过缓存映射结果来减少不必要的计算。 在选择...
在实际应用中,BeanUtils可以极大地简化Java对象属性的访问和修改过程,尤其是在需要处理大量数据或进行复杂业务逻辑时。它提供了一种方便、统一的方式来操作JavaBean,使得开发者可以更专注于业务逻辑的实现,而非...
Apache Commons BeanUtils 是一个流行的Java工具库,主要用于简化对象属性的访问和操作。这个库提供了许多实用方法,帮助开发者更方便地处理Java Bean对象。在"commons-beanutils-1.9.2-src"这个压缩包中,我们得到...
8. **拷贝属性**:`copyProperties()`方法允许将一个JavaBean的属性值复制到另一个JavaBean,这对于对象的克隆和属性值的传递非常有用。 9. **模块化设计**:Apache Commons BeanUtils是Apache Commons项目的一部分...