java之深拷贝和浅拷贝

一、Object类的clone方法

1、说明

Object类的clone方法是native方法

什么是Native Method?简单地讲,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C/C++语言

2、代码

protected native Object clone() throws CloneNotSupportedException;

二、利用系列化发序列化的clone方法

1、说明

被克隆的对象需要继承Serializable接口

2、代码

import java.io.*;

/**
 * 深度clone工具类,被clone的类必须是序列化了,否则会报错
 * 利用对象的序列化、反序列化达到深度clone
 */
public class CloneUtil {
    public static  T clone(T obj) {

        T clonedObj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            clonedObj = (T) ois.readObject();
            ois.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

        return clonedObj;
    }
}

三、实验对比

1、类对象

public class Identity implements Serializable {

    private static final long serialVersionUID = 4980693168901248332L;

    private String idNo;

    private List schoolingNames;

    private Integer age;

    public String getIdNo() {
        return idNo;
    }

    public void setIdNo(String idNo) {
        this.idNo = idNo;
    }

    public List getSchoolingNames() {
        return schoolingNames;
    }

    public void setSchoolingNames(List schoolingNames) {
        this.schoolingNames = schoolingNames;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
public class User implements Serializable, Cloneable{

    private static final long serialVersionUID = 1835115164855723296L;

    private String userName;
    private String password;

    private Identity identity;


    @Override
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }

    public Identity getIdentity() {
        return identity;
    }

    public void setIdentity(Identity identity) {
        this.identity = identity;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

2、 测试代码

public class CloneTest {

    public static void main(String[] args) {
        try {
            test1();

            System.out.println("======================");

            test2();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }


    private static void test1() throws CloneNotSupportedException {
        long start = System.currentTimeMillis();

        // 封装user1
        Identity identity = new Identity();
        identity.setAge(10);
        identity.setIdNo("00000000000000");

        List schoolNames = new ArrayList<>();
        schoolNames.add("家里蹲大学");
        identity.setSchoolingNames(schoolNames);

        User user1 = new User();
        user1.setUserName("wangteng");
        user1.setPassword("123456");
        user1.setIdentity(identity);

        // 利用Object的原生clone()方法clone一个对象user2
        User user2 = (User) user1.clone();

        // 比较user1和user2的引用
        boolean result1 = user1==user2;
        System.out.println("user1 == user2 : " + result1);

        // 比较user1和user2的简单类型的属性password属性(String类型,比较特殊点)
        boolean result2 = user1.getPassword()==user2.getPassword();
        System.out.println("user1.getPassword() == user2.getPassword() : " + result2);

        // 比较user1和user2的复杂类型的属性identity属性
        boolean result3 = user1.getIdentity()==user2.getIdentity();
        System.out.println("user1.getIdentity() == user2.getIdentity() : " + result3);

        System.out.println("花费时间:" + (System.currentTimeMillis()-start) + "ms");
    }


    private static void test2() throws CloneNotSupportedException {
        long start = System.currentTimeMillis();

        // 封装user1
        Identity identity = new Identity();
        identity.setAge(10);
        identity.setIdNo("00000000000000");

        List schoolNames = new ArrayList<>();
        schoolNames.add("家里蹲大学");
        identity.setSchoolingNames(schoolNames);

        User user1 = new User();
        user1.setUserName("wangteng");
        user1.setPassword("123456");
        user1.setIdentity(identity);

        // 利用对象的序列化、反序列化达到深度clone
        User user2 = CloneUtil.clone(user1);

        // 比较user1和user2的引用
        boolean result1 = user1==user2;
        System.out.println("user1 == user2 : " + result1);

        // 比较user1和user2的简单类型的属性password属性(String类型,比较特殊点)
        boolean result2 = user1.getPassword()==user2.getPassword();
        System.out.println("user1.getPassword() == user2.getPassword() : " + result2);

        // 比较user1和user2的复杂类型的属性identity属性
        boolean result3 = user1.getIdentity()==user2.getIdentity();
        System.out.println("user1.getIdentity() == user2.getIdentity() : " + result3);

        System.out.println("花费时间:" + (System.currentTimeMillis()-start) + "ms");
    }

}

3、输出

user1 == user2 : false
user1.getPassword() == user2.getPassword() : true
user1.getIdentity() == user2.getIdentity() : true
花费时间:3ms
======================
user1 == user2 : false
user1.getPassword() == user2.getPassword() : false
user1.getIdentity() == user2.getIdentity() : false
花费时间:65ms

四、说明

从上可以看出:
1、Object类的native方法clone()实现的是浅拷贝,序列化反序列化实现的是深拷贝。
2、二者从效率上来看,clone方法由于实现的是浅拷贝同时是native方法,所以效率远远比序列化反序列化的深拷贝来的高。

你可能感兴趣的:(java之深拷贝和浅拷贝)