浅克隆与深克隆

Posted zoey686

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅克隆与深克隆相关的知识,希望对你有一定的参考价值。

深克隆与浅克隆的区别

 

一、clone()是什么

Object.clone() 

  clone是Object的方法,在使用clone()方法时需要调用Clonable这个接口,Cloneable()这个接口是一个空接口,在不实现Cloneable接口的实例上调用对象的克隆方法导致抛出异常CloneNotSupportedException。

  

如果Clonable是个空接口,那么为什么还需要使用呢?

举个例子:如果一个对象不能被clone,则不实现Cloneable接口,如果有其它对象对此对象进行拷贝时,则会抛出CloneNotSupportedException。

所以说空接口即为标识接口,标识接口中没有任何方法的定义,其作用是告诉这些接口的实现类是否具有某个功能,比如是否支持克隆。

 

二、怎么clone

举个例子:

public class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Person{" +
                "name=‘" + name +  +
                ", age=" + age +
                };
    }
}

 

public class NewPerson implements Cloneable {
    private String s;
    private int i;
    Person p;   //上面的类

    public NewPerson(String s, int i, Person p) {
        this.s = s;
        this.i = i;
        this.p = p;
    }


/*
进行Clone
所有类都默认继承Object,所以我们调用Clone是在调用父类的方法
*/
public NewPerson clone() { NewPerson np = null; try { np = (NewPerson) super.clone(); System.out.println("Supper: " + super.toString()); } catch (Exception e) { e.printStackTrace(); } return np; } @Override public String toString() { return "NewPerson{" + "s=‘" + s + + ", i=" + i + ", p=" + p + }; } }

 

public class Main {
    public static void main(String[] args) {
        Person p = new Person("WangWu", 22);
        NewPerson p1 = new NewPerson("aaa", 1, p);
        NewPerson p2 = p1.clone();

        System.out.println("p1: " + p1.toString());    //p1: Person{s=‘aaa‘, i=1, p=Person{name=‘WangWu‘, age=22}}
        System.out.println("p2: " + p2.toString());   //p2: Person2{s=‘aaa‘, i=1, p=Person{name=‘WangWu‘, age=22}}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
System.out.println(p1 == p2);    //false System.out.println(p1.p == p2.p);  //true } }

 

补充知识点: “==”比较地址,地址相同可表示同一个对象

 

现在你只需要看到//////上面,知道我们的clone调用成功了即可,并且知道如何使用clone

 

三、代码分析

p2 = p1.clone()

从输出的值我们可以知道p1 和 p2 的值相等

现在需要看////下面的输出了

p1 == p2  为 false:  p1和p2的地址不同,不是同一个对象, 说明clone并不是引用,而是的的确确又新建立了一个对象

p1.p == p2.p 为 true:p1.p和p2.p的地址相同,说明NewPerson 中引用对象Person 在Clone中没有新建立对象,即p2.p没有新建立对象,而是指向了原有的p1.p

 

总结:B = A.clone() , A调用clone方法,新创建一个对象B,B中基本类型与A的基本类型相等,但是对于A中的引用对象,B中不进行创建,而是引用A中的引用对象。

 

四、深克隆与浅克隆

浅克隆就是与clone方法一样,新创立一个克隆的对象,但对于被克隆对象中的引用对象却不创建,而是引用被克隆对象中的。

深克隆也是创建一个对象,但是被克隆对象中的引用对象也会被重新创建。

 

图中即为上面代码深克隆和浅克隆的示意图

浅克隆 p1, p2对象都指向 p, 深克隆则是新创建了一个p

技术图片

 

 

 

 

五、序列化实现深克隆

序列化与克隆一样也有一个空接口:Serializable

序列化:是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。是java提供的一种保存对象状态的机制。

 

序列化的使用场景:①将内存中对象保存到一个文件中或数据库中 ②将对象通过网络进行传播的时候

 

演示代码:

package com.zoey.java.clone;

import java.io.Serializable;

//Person也需要继承Serializable接口,因为将NewPerson写入流中,也要讲Person写入流
public class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name=‘" + name + + ", age=" + age + }; } }
package com.zoey.java.clone;

import java.io.*;

public class NewPerson implements Serializable {
    Person p;
    int i;
    String s;

    public NewPerson(Person p, int i, String s) {
        this.p = p;
        this.i = i;
        this.s = s;
    }

    public Object deepClone() throws IOException, ClassNotFoundException {
            //将对象写入流中
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bao);
            oos.writeObject(this);

            //将对象从流中取出
            ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (ois.readObject());
    }

    @Override
    public String toString() {
        return "NewPerson{" +
                "p=" + p +
                ", i=" + i +
                ", s=‘" + s +  +
                };
    }
}
package com.zoey.java.clone;

import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person p = new Person("WangWu", 22);
        NewPerson p1 = new NewPerson(p,1,"aaa");
        NewPerson p2 = (NewPerson) p1.deepClone();

        System.out.println("p1: " + p1.toString());
        System.out.println("p2: " + p2.toString());

        System.out.println(p1 == p2);       //false
        System.out.println(p1.p == p2.p);   //false
    }
}

均不相等说明都创建了新的引用对象,而不是同一个引用

 

以上是关于浅克隆与深克隆的主要内容,如果未能解决你的问题,请参考以下文章

浅克隆与深克隆

原型模式(克隆模式)—浅谈浅克隆与深克隆

Jquery浅克隆与深克隆

Jquery浅克隆与深克隆

JAVA浅复制与深复制

原型模式案例详解-浅拷贝与深拷贝