Java 深拷贝和浅拷贝的应用

原理啥的就不深入介绍了,主要记录下 几个 对象复制的方法。

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);
}

如果还有更好的请补充。。

你可能感兴趣的:(基础知识)