JavaBean拷贝
深拷贝和浅拷贝概念
浅拷贝 Shallow Copy
对基本类型的属性会进行值传递,当修改其中一个对象中的属性时,不会影响另一个对象中的属性
对引用数据的属性,比如数组或某类对象,会进行引用传递,及两个对象中的属性指向同一个实例对象,修改对象会相互影响。
深拷贝 Deep Copy
深拷贝就是对引用类型的数据,也进行拷贝,开辟新的内存空间,两个bean之间相互修改自己的属性不产生影响。
开源工具类
- apache的BeanUtils 原理-反射
- apache的PropertyUtils 原理-反射
- spring的BeanUtils 原理-反射
- cglib的BeanCopier 原理-动态代理,性能很高,是反射的几十倍或数百倍
说明:反射的性能很差,有人做过这几种拷贝工具的性能测试,发现通过反射实现的功能性能很差,不建议在生产环境使用
BeanCopiers使用说明
注意事项
BeanCopier只有在属性名称和类型都相同的情况下才会进行copy。
工具类用例1(使用同步锁)
/**
* BeanCopier工具类, 运用了享元模式进行实现
*
* @author icetea
*/
public class BeanCopierUtils {
/**
* BeanCopier缓存(享元模式)
*/
private static Map<String, BeanCopier> beanCopierCacheMap = new HashMap<>();
/**
* 将source对象的属性拷贝到target对象中去
*
* @param source source对象
* @param target target对象
*/
public static void copyProperties(Object source, Object target) {
String cacheKey = source.getClass().toString() + target.getClass().toString();
BeanCopier beanCopier = null;
// 为了线程安全使用双重锁机制
if (!beanCopierCacheMap.containsKey(cacheKey)) {
synchronized (BeanCopierUtils.class) {
if (!beanCopierCacheMap.containsKey(cacheKey)) {
// 进入到这里会创建一个BeanCopier实例并且放在缓存map中
beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
beanCopierCacheMap.put(cacheKey, beanCopier);
} else {
beanCopier = beanCopierCacheMap.get(cacheKey);
}
}
} else {
beanCopier = beanCopierCacheMap.get(cacheKey);
}
beanCopier.copy(source, target, null);
}
}
工具类用例1(使用jdk8的concurrentHashMap)
/**
* BeanCopier工具类, 运用了享元模式进行实现
*
* @author icetea
*/
public class BeanCopierUtils {
/**
* BeanCopier缓存(享元模式)
*/
private static final Map<String, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();
/**
* 将source对象的属性拷贝到target对象中去
*
* @param source source对象
* @param target target对象
*/
public static void copyProperties(Object source, Object target) {
String cacheKey = source.getClass().toString() + target.getClass().toString();
// 查看concurrentHashMap的实现方法介绍可以得知该方法为原子方法,保证了线程安全
BeanCopier beanCopier = BEAN_COPIER_MAP.computeIfAbsent(cacheKey, k -> BeanCopier.create(source.getClass(), target.getClass(), false));
beanCopier.copy(source, target, null);
}
}