1.浅拷贝和深拷贝的区别
1.1浅拷贝
对于对象中的基本类型来说,浅拷贝进行拷贝的时候,进行的是值传递,而对引用类型的进行拷贝的时候,进行拷贝的仅仅是引用类型的引用地址而已,并没有进行新建一个对象,并将被拷贝对象中的成员变量拷贝过去。
1.2深拷贝
深拷贝较于浅拷贝的区别就是,深拷贝进行拷贝引用类型数据的时候,新建了一个对象,并将被拷贝对象的成员变量的值复制到了新对象里。
2.ApacheBeanUtils和Spring的BeanUtils的源码分析
2.1ApacheBeanUtils
ApacheBeanUtil的copyProperties先进性判断了拷贝对象和被拷贝对象是否为空值,又进行了判断对象是否实现了DynaBean接口,实现了该接口的还要进行复杂的类型转换,没有实现该接口的又进行判断是否实现了Map接口,同样如果实现了Map接口也要进行复杂的类型转换,如果没有实现DynaBean/Map就进入最后一个分支语句,在三中情况里,两种对JAVA自封装的对象进行拷贝的时候,都使用了反射,判断属性的可读性,可写性,综合下来,使用了判断空指针,类型转换,反射等,这一套下来,十分消耗性能,如果进行大量的对象拷贝可能会消耗大量的时间。
public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {
if (dest == null) {
throw new IllegalArgumentException("No destination bean specified");
} else if (orig == null) {
throw new IllegalArgumentException("No origin bean specified");
} else {
if (this.log.isDebugEnabled()) {
this.log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + ")");
}
int var5;
int var6;
String name;
Object value;
if (orig instanceof DynaBean) {
DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();
DynaProperty[] var4 = origDescriptors;
var5 = origDescriptors.length;
for(var6 = 0; var6 < var5; ++var6) {
DynaProperty origDescriptor = var4[var6];
name = origDescriptor.getName();
if (this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {
value = ((DynaBean)orig).get(name);
this.copyProperty(dest, name, value);
}
}
} else if (orig instanceof Map) {
Map<String, Object> propMap = (Map)orig;
Iterator var13 = propMap.entrySet().iterator();
while(var13.hasNext()) {
Map.Entry<String, Object> entry = (Map.Entry)var13.next();
String name = (String)entry.getKey();
if (this.getPropertyUtils().isWriteable(dest, name)) {
this.copyProperty(dest, name, entry.getValue());
}
}
} else {
PropertyDescriptor[] origDescriptors = this.getPropertyUtils().getPropertyDescriptors(orig);
PropertyDescriptor[] var14 = origDescriptors;
var5 = origDescriptors.length;
for(var6 = 0; var6 < var5; ++var6) {
PropertyDescriptor origDescriptor = var14[var6];
name = origDescriptor.getName();
if (!"class".equals(name) && this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {
try {
value = this.getPropertyUtils().getSimpleProperty(orig, name);
this.copyProperty(dest, name, value);
} catch (NoSuchMethodException var10) {
}
}
}
}
}
}
2.2SpringBean源码的分析
进行读取SpringBean的源码后发现,先是判断了被拷贝对象是否可以编辑,如果可以编辑就获得可编辑对象,获取到背靠背对象的全部属性,并且还可以进行判断那些属性是被忽略不进行拷贝的,在循环拷贝中,也仅仅是尽心判断了对象的可读性和可写性,属性的可读性和可写性等,并没有进行大量的类型转换,实例判断等,这样就在大量对象进行拷贝的时候,节约了性能,提高了加载速度等。
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null) {
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
boolean isAssignable = !sourceResolvableType.hasUnresolvableGenerics() && !targetResolvableType.hasUnresolvableGenerics() ? targetResolvableType.isAssignableFrom(sourceResolvableType) : ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType());
if (isAssignable) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
} catch (Throwable var18) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var18);
}
}
}
}
}
}
3.总结
3.1性能总结
Spring的BeanUtils优于Apache的BeanUtils.
3.2安全性总结
都很安全。
3.3阿里巴巴规约
阿里巴巴嵩山版JAVA规约中指出,不建议使用Apache的BeanUtils,建议使用Spring的BeanUtils或者BeanCopier、PropertieyUtils等进行对象的拷贝。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。