浅克隆与深克隆

    xiaoxiao2023-10-02  157

    什么是克隆 获得一个对象和原对象一样用到的场景 在java中对引用类型的对象进行赋值运算时,不会创建新的对象,只会传递当前对象的一个引用。假如现在已经有了一个对象,该对象中存在一些属性,这时候就要用到克隆来得到一个和他一样的全新对象。而且clone是native方法,效率远高于new使用的基本条件 要使用克隆方法,必须实现Cloneable接口,并重写object类中的clone()方法。Cloneable这个接口是一个空接口,只是一个表示,如果没有实现该接口,进行克隆的时候会抛出CloneNotSupportedException异常。 基本使用如下: public class Student implements Cloneable{ String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } 深拷贝与浅拷贝 浅拷贝是指只拷贝对象本身(包括对象中的基本变量),而不对对象中的引用进行二次拷贝。举例说明:现在有个Student类,有一个Person类,在person类中包含了一个Student类的属性,如果对person类的一个对象进行克隆,克隆得到的对象中的Student属性的引用和原person对象是指向同一个Student对象。测试如下:

    Student类:

    public class Student implements Cloneable{ String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

    Person类:

    public class Person implements Cloneable{ int age; String name; Student student; public Person(int age, String name, Student student) { this.age = age; this.name = name; this.student = student; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

    测试类:

    public class Test { public static void main(String []args) throws Exception{ Student student = new Student("小明", 12); Person person = new Person( 13,"李四", student); Person person1 =(Person) person.clone(); System.out.println("改变之前"); System.out.println("原对象的基本属性:" + person.name + "," + person.age); System.out.println("拷贝对象的基本属性:" + person1.name + "," + person1.age); System.out.println("原对象的student:" + person.student); System.out.println("拷贝对象的student:" + person1.student); //对拷贝对象的student属性改变 person1.student.age = 100; person1.student.name = "小红"; System.out.println("改变之后"); System.out.println("改变后原对象的student:" + person.student); System.out.println("改变后拷贝对象的student:" + person1.student); } }

    测试结果:

    改变之前 原对象的基本属性:李四,13 拷贝对象的基本属性:李四,13 原对象的student:Student{name='小明', age=12} 拷贝对象的student:Student{name='小明', age=12} 改变之后 改变后原对象的student:Student{name='小红', age=100} 改变后拷贝对象的student:Student{name='小红', age=100}

    可以看到,原对象的Student属性随着克隆对象的Student属性的改变而进行了改变,说明没有对Student属性进行克隆,只是传递了一个引用。这就是浅拷贝,如果没有对clone()方法进行改写,那么默认就是浅拷贝。那么如何进行深拷贝呢?下面给出示例 在Person类中对clone()方法进行改写:

    public class Person implements Cloneable{ int age; String name; Student student; public Person(int age, String name, Student student) { this.age = age; this.name = name; this.student = student; } @Override protected Object clone() throws CloneNotSupportedException { Student student =(Student) this.student.clone(); Person person =(Person) super.clone(); person.student = student; return person; } }

    测试结果:

    改变之前 原对象的基本属性:李四,13 拷贝对象的基本属性:李四,13 原对象的student:Student{name='小明', age=12} 拷贝对象的student:Student{name='小明', age=12} 改变之后 改变后原对象的student:Student{name='小明', age=12} 改变后拷贝对象的student:Student{name='小红', age=100}

    可见,实现了深拷贝。 实现深拷贝还有另外一种方法,就是通过序列化获取原对象 Student类:

    public class Student implements Serializable { String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

    Person类:

    import java.io.*; public class Person implements Serializable { int age; String name; Student student; public Person(int age, String name, Student student) { this.age = age; this.name = name; this.student = student; } public Person deepCopy(){ try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (Person) oi.readObject(); } catch (Exception e) { e.printStackTrace(); } return null; } }

    测试类:

    public class Test { public static void main(String []args) throws Exception{ Student student = new Student("小明", 12); Person person = new Person( 13,"李四", student); Person person1 =person.deepCopy(); System.out.println("改变之前"); System.out.println("原对象的基本属性:" + person.name + "," + person.age); System.out.println("拷贝对象的基本属性:" + person1.name + "," + person1.age); System.out.println("原对象的student:" + person.student); System.out.println("拷贝对象的student:" + person1.student); //对拷贝对象的student属性改变 person1.student.age = 100; person1.student.name = "小红"; System.out.println("改变之后"); System.out.println("改变后原对象的student:" + person.student); System.out.println("改变后拷贝对象的student:" + person1.student); } }

    测试结果:

    改变之前 原对象的基本属性:李四,13 拷贝对象的基本属性:李四,13 原对象的student:Student{name='小明', age=12} 拷贝对象的student:Student{name='小明', age=12} 改变之后 改变后原对象的student:Student{name='小明', age=12} 改变后拷贝对象的student:Student{name='小红', age=100}

    但是这样很耗时,不建议

    最新回复(0)