原理啥的就不深入介绍了,主要记录下 几个 对象复制的方法。
1. 实现 Cloneable 接口 浅拷贝
2. Apache的两个版本:(反射机制)
org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig) org.apache.commons.beanutils.BeanUtils#cloneBean
3.Spring版本:(反射机制)
org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)
4.cglib版本:(使用动态代理,效率高)create的实例可缓存,就不需要每次创建
net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)
/**
* 深拷贝和浅拷贝,对象复制的实践
*/
public class Demo11_Clone {
/**
*深拷贝
*
* 相当于创建了一个新的对象,只是这个对象的所有内容,都和被拷贝的对象一模一样而已,即两者的修改是隔离的,相互之间没有影响\n
*
* 浅拷贝\n
*
* 也是创建了一个对象,但是这个对象的某些内容(比如A)依然是被拷贝对象的,即通过这两个对象中任意一个修改A,两个对象的A都会受到影响
*
*/
// 浅拷贝
/**
* 1. 实现 Cloneable 接口
* 浅拷贝的整个过程就是,创建一个新的对象,然后新对象的每个值都是由原对象的值,通过 = 进行赋值
*/
// 需新建类,内部类执行的时候会报错
// class Students implements Cloneable {
//
// private String name;
// private Teacher teacher;
//
// public Students() {
// }
//
// public Students(String name, Teacher teacher) {
// this.name = name;
// this.teacher = teacher;
// }
//
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
//
// public Teacher getTeacher() {
// return teacher;
// }
//
// public void setTeacher(Teacher teacher) {
// this.teacher = teacher;
// }
//
// @Override
// public Students clone() {
// Students students = null;
// try {
// students = (Students) super.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return students;
// }
// }
//
// class Teacher{
//
// private String name;
//
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }
// }
/**
* 2. 深拷贝
*
* 接着上面的浅拷贝的例子 如何改成深拷贝呢?
*
* clone() 方法替换成 deepClone() 就可以深拷贝
*
* 简单来说,深拷贝是需要自己来实现的,对于基本类型可以直接赋值,而对于对象、容器、数组来讲,需要创建一个新的出来,然后重新赋值
*
* 问题是 如果一个类有很多对象,每个都要自己创建复制,那么这样就很繁琐了,也不利于开发
*
* 这里将给出几个 利用反射或动态代理来完成深拷贝的类库。
*/
public Students deepClone() {
Students students = null;
try {
students = (Students) super.clone();
Teacher orgin = students.getTeacher();
if (orgin != null) {
Teacher teacher = new Teacher();
teacher.setName(orgin.getName());
students.setTeacher(new Teacher());
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return students;
}
/**
* 3. 对象拷贝工具
*
* 浅拷贝,需要实现Clonebale接口,深拷贝一般需要自己来实现,那么我现在拿到一个对象A,它自己没有提供深拷贝接口,我们除了主动一条一条的帮它实现之外,有什么辅助工具可用么?
*
* 对象拷贝区别与clone,它可以支持两个不同对象之间实现内容拷贝
*
* Apache的两个版本:(反射机制)
*
* org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)
*
* org.apache.commons.beanutils.BeanUtils#cloneBean
* ---------------------
*/
// org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)
public void deepCopyByApache() {
Demo11_Clone demo11_clone = new Demo11_Clone();
Students students = new Students();
students.setName("zz");
Teacher teacher = new Teacher();
teacher.setName("TT");
students.setTeacher(teacher);
try {
Object newBean = students.getClass().newInstance();
PropertyUtils.copyProperties(newBean, students);
System.out.println("PropertyUtils 深拷贝:" + (students.getTeacher() == ((Students) newBean).getTeacher()));
} catch (Exception ex) {
ex.printStackTrace();
}
//org.apache.commons.beanutils.BeanUtils#cloneBean
// apache 的另一个版本,其实也是用 copyProperties() 方法。
}
/**
* 4. Spring版本:(反射机制)
* org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)
*
* String[] ignoreProperties 设置 拷贝的时候,忽略复制的字符串 为 null。
*
* 源对象 和 目标对象存在相同的字段的话就会被赋值
* 坑点:BeanUtils所花费的时间要超过取数 据、将其复制到对应的 value对象(通过手动调用get和set方法),以及通过串行化将其返回到远程的客户机的时间总和
*/
public void copyBySpring() {
Demo11_Clone demo11_clone = new Demo11_Clone();
Students students = new Students();
students.setName("zz");
Teacher teacher = new Teacher();
teacher.setName("TT");
students.setTeacher(teacher);
try {
Object newBean = students.getClass().newInstance();
BeanUtils.copyProperties(students, newBean);
System.out.println("Spring 浅拷贝:" + (students.getTeacher() == ((Students) newBean).getTeacher()));
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 5.cglib版本:(使用动态代理,效率高)create的实例可缓存,就不需要每次创建
* net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)
*/
public void copyByCglib() {
Demo11_Clone demo11_clone = new Demo11_Clone();
Students students = new Students();
students.setName("zz");
Teacher teacher = new Teacher();
teacher.setName("TT");
students.setTeacher(teacher);
try {
Object newBean = students.getClass().newInstance();
//第三个参数useConverter,是否开启Convert。默认BeanCopier只会做同名,同类型属性的copier,
// 否则就会报错。如果类型需要转换比如Date转换成String则自定义Convert类实现Convert接口。
BeanCopier copier = BeanCopier.create(Students.class, newBean.getClass(), false);
copier.copy(students, newBean, null);
System.out.println("cglib 浅拷贝:" + (students.getTeacher() == ((Students) newBean).getTeacher()));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String args[]) {
Demo11_Clone demo11_clone = new Demo11_Clone();
Students students = new Students();
students.setName("zz");
Teacher teacher = new Teacher();
teacher.setName("TT");
students.setTeacher(teacher);
Students tV2 = students.clone();
// 可得知,是相同的对象
System.out.println("clone 浅拷贝" + (students.getTeacher() == tV2.getTeacher()));
demo11_clone.deepCopyByApache();
demo11_clone.copyBySpring();
demo11_clone.copyByCglib();
}
5. 还有个版本 结合序列化与 反序列化 可深拷贝一个对象。
运用 protostuff 类库的序列化和反序列化工具 实现。
publlic static T deepCopy(Class clazz,T object){
byte[] bytes = serial(class,object);
return deserail(class,bytes);
}
如果还有更好的请补充。。