文档章节

Java中对象的深克隆和浅克隆

Jia
 Jia
发布于 2016/08/20 13:33
字数 1163
阅读 40
收藏 2

浅克隆和深克隆的概念

        浅克隆:被克隆的对象里的所有变量值都与原来的对象相同,而所有对其他对象的引用仍然指向原来的对象。简而言之,浅克隆仅仅克隆当前对象,而不克隆当前对象所引用的对象。

        深克隆:被克隆的对象里的所有变量值都与原来的对象相同,那些引用其他对象的变量将指向被复制过的新对象,而不再是原来被引用的对象。简而言之,深克隆不仅克隆了当前对象,还把当前对象所引用的对象都复制了一遍。

 

Java中的clone()方法

        Object类中的clone()方法属于浅克隆。它的工作原理是:先在内存中开辟一块和原始对象相同大小的空间,然后原样复制原始对象中的内容。对于基本数据类型,这样操作是没问题的。但对于非基本数据类型,由于它们所保存的仅仅是对象的引用,如果不进行更深层次的克隆,就会导致克隆后的对象引用和原始对象中相应的对象引用所指向的是同一个对象。

 

使用clone()方法实现浅克隆

        在要克隆的类中实现Cloneable接口,覆盖Object类中的clone()方法,并声明为public。同时在clone()方法中,调用super.clone()返回克隆后的对象。请看以下代码:

class Professor {
    String name;
    int age;

    public Professor(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student implements Cloneable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws CloneNotSupportedException {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.clone();

        System.out.println("Before change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("student1's professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("Student1's professor age = " + student1.professor.age);
    }
}

 

使用clone()方法实现深克隆

        通过以上代码可以证明Java中的clone()方法是浅克隆,那应该如何实现更深层次的克隆呢?请看以下代码:

class Professor implements Cloneable {
    String name;
    int age;

    public Professor(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Professor clone() throws CloneNotSupportedException {
        return (Professor) super.clone();
    }
}

class Student implements Cloneable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.professor = student.professor.clone();
        return student;
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws CloneNotSupportedException {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.clone();

        System.out.println("Before change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("student1's professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("Student1's professor age = " + student1.professor.age);
    }
}

        在以上代码中,虽然通过在Student类中调用Professor类中覆盖的clone方法来对professor成员进行克隆从而实现了深克隆,但也由此可见,如果克隆类中的引用类型变量有多个的情况下,采用这种方式实现深克隆将会非常复杂。

 

使用对象序列化和反序列化实现深克隆(推荐

        把对象写到字节流里的过程是序列化(Serilization)的过程,而把对象从字节流中读出来的过程是反序列化(Deserialization)的过程。由于在Java 序列化的过程中,写在流里的是对象的一个拷贝,而原对象仍然在JVM里,所以可以利用这个原理来实现对对象的深克隆。请看以下代码:

class Professor implements Serializable {
    String name;
    int age;

    public Professor(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student implements Serializable {
    String name;
    int age;
    Professor professor;

    public Student(String name, int age, Professor professor) {
        this.name = name;
        this.age = age;
        this.professor = professor;
    }

    public Student deepClone() throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(this);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        return (Student) objectInputStream.readObject();
    }
}

public class CloneTutorial {
    public static void main(String[] args) throws Exception {
        Professor professor = new Professor("Galler", 50);
        Student student1 = new Student("Tom", 18, professor);
        Student student2 = student1.deepClone();

        System.out.println("Before change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("student1's professor age = " + student1.professor.age);

        student2.professor.name = "Mary";
        student2.professor.age = 30;

        System.out.println();
        System.out.println("After change student2's professor");
        System.out.println("Student1's professor name = " + student1.professor.name);
        System.out.println("Student1's professor age = " + student1.professor.age);
    }
}

 

总结

        虽然使用Java的clone()方法实现浅克隆以及深克隆更加直观,但是针对每一个需要克隆的类都必须单独实现一个clone()方法,导致其扩展性并不好。而使用对象序列化与反序列化来实现深克隆,能使代码更简洁,更通用。此处推荐使用后者。

© 著作权归作者所有

Jia

Jia

粉丝 66
博文 13
码字总数 23840
作品 0
海淀
程序员
私信 提问
Java拾遗:008 - 对象克隆与浅拷贝、深拷贝

对象克隆 Object类中有一个方法叫,完整代码 首先它是一个Native方法,而且是受保护的(),抛出一个异常(JDK1.8)。 通常程序员自己定义的类不能直接调用方法,如果要在外部调用,需要重写...

一别丶经年
2018/08/04
59
0
Java中如何克隆集合——ArrayList和HashSet深拷贝

编程人员经常误用各个集合类提供的拷贝构造函数作为克隆,,,或者其他集合实现的方法。需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味着存储在原始List和克隆List中...

markGao
2014/04/18
1K
0
Java中如何克隆集合——ArrayList和HashSet深拷贝

编程人员经常误用各个集合类提供的拷贝构造函数作为克隆List,Set,ArrayList,HashSet或者其他集合实现的方法。需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味着存...

LCZ777
2014/04/14
89
0
Java中的克隆Cloneable

浅克隆与深克隆 当拷贝一个变量时,原始变量与拷贝变量引用了同一个对象。那么当改变一个变量所引用的对象时,就会对另一个变量产生影响。形象化一点说,就像某人A有一把遥控,用来控制电视,...

静水楼台
2013/06/04
219
0
深入理解原型模式 ——通过复制生成实例

Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):https://github.com/Snailclimb/Java_Guide一 原型模式介绍 在面向对象系统中,使用原型模式来复制一个对象自...

Amsour丶
2018/06/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

JavaScript设计模式——适配器模式

  适配器模式是设计模式行为型模式中的一种模式;   定义:   适配器用来解决两个已有接口之间不匹配的问题,它并不需要考虑接口是如何实现,也不用考虑将来该如何修改;适配器不需要修...

有梦想的咸鱼前端
28分钟前
3
0
Andorid SQLite数据库开发基础教程(1)

Andorid SQLite数据库开发基础教程(1) Android数据库访问方式 SQLite是Android系统默认支持的文件数据库。该数据库支持SQL语言,适合开发人员上手。本教程将讲解如何开发使用SQLite的Andro...

大学霸
31分钟前
3
0
Handler简解

Handler 这里简化一下代码 以便理解 Handler不一定要在主线程建 但如Handler handler = new Handler(); 会使用当前的Looper的, 由于要更新UI 所以最好在主线程 new Handler() { mLooper = Lo...

shzwork
53分钟前
4
0
h5获取摄像头拍照功能

完整代码展示: <!DOCTYPE html> <head> <title>HTML5 GetUserMedia Demo</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum......

诗书易经
55分钟前
3
0
正向代理和反向代理

文章来源 运维公会:正向代理和反向代理 1、正向代理 (1)服务对象不同 正向代理服务器的服务对象是客户端,可以将客户端和代理服务器看作一个整体。 (2)配置方法不同 需要在客户端配置代...

运维团
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部