Java的浅度克隆和深度克隆

来源:互联网 发布:网络端口怎么拆下来 编辑:程序博客网 时间:2024/05/17 04:02

前言:

protected native Object clone() throws CloneNotSupportedException

方法由protected修饰,只能由子类重写和调用,而且为本地方法。

Object提供clone方法,生成对象的一个副本,来实现对象的一次浅度克隆。但是对象的引用类型不会拷贝一份,引用地址与原对象相同。

实现对象的克隆需要实现Cloneable接口,重写clone方法,通过super.clone()调用Object类的clone方法得到当前对象的副本,并放回该副本。


浅度克隆与深度克隆的区别:

浅度克隆:基本类型都会拷贝一份,引用类型引用地址不变,还是同一个对象。

深度克隆:基本类型和引用类型都会拷贝一份,完完全全的是不同的两份,引用地址不一样。


下面结合一个具体的例子:(两者结合)

定义person类:(实现了Cloneable接口)

class Person implements Cloneable{    int id;    public Person(int id) {        this.id = id;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}
定义Student类(实现Cloneable接口)

public class Student implements Cloneable{    private int age;  //基本类型    private String name;  //引用类型,未实现自己的深度拷贝    private Person person;  //引用类型,Person类实现了Cloneable接口,深度拷贝    public Student(int age, String name, Person person) {        this.age = age;        this.name = name;        this.person = person;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Person getPerson() {        return person;    }    public void setPerson(Person person) {        this.person = person;    }    @Override    protected Object clone() throws CloneNotSupportedException {        Student student = (Student) super.clone();          Person person = (Person) student.getPerson().clone();  //这个为重点,把student里面的引用类型person深度克隆        student.setPerson(person);        return student;    }    public static void main(String[] args) throws Exception{        Person person = new Person(2);        Student student1 = new Student(10,"wqh", person);        Student student2 = (Student) student1.clone();        System.out.println(student1 == student2);  //false        System.out.println(student1.getName()==student2.getName()); //true        System.out.println(student1.getPerson() == student2.getPerson());  //false    }}

输出结果:
falsetruefalse

分析:

Student中有两个引用类型:String和Person,在Person中实现了clone接口,在Student的clone方法中我们对person属性也进行了一次深度克隆,这样对student1拷贝成student2后,各自的person属性是单独的两份,引用地址不一样,所以为false,但是string属性是同一份,故为true。综述,对student2而言,这是一次不彻底的深度克隆,因为部分引用属性没有进行深度克隆。

画个图来明了下:


student1和student2对应于堆中的同一个name,不同的person。