Java - 关于 Cloneable 接口 clone 方法(二)

简介: Java - 关于 Cloneable 接口 clone 方法(二)

2、如何实现深克隆

还是上面的例子,我们改下代码


class Model2 implements Cloneable{
    int height;
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("clone Model2");
        return super.clone();
    }
}
public class CloneModel implements Cloneable{
    private String name;
    private int age;
    private Model2 model2;
    public CloneModel() {
        this.model2 = new Model2();
    }
    public Model2 getModel2() {
        return model2;
    }
    public void setModel2(Model2 model2) {
        this.model2 = model2;
    }
    @Override
    public CloneModel clone() throws CloneNotSupportedException {
        CloneModel cloneModelTemp = (CloneModel)super.clone();
        cloneModelTemp.setModel2((Model2)cloneModelTemp.getModel2().clone());
        return cloneModelTemp;
    }
    @Override
    public String toString() {
        return "CloneModel{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

再次测试下

public static void main(String[] args) throws CloneNotSupportedException {
    CloneModel cloneModel1 = new CloneModel();
    CloneModel cloneModel2 = cloneModel1.clone();
    System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
}

输出


false

这么做就要在super.clone的基础上 继续对非基本类型的对象递归的再次clone。显然这么方式是繁琐的且不可靠的。有没有其他的方式呢?序列化

3、序列化实现深度克隆

(1)使用java自身的序列化转为二进制数 ,再反序列化为对象

上面的例子改造下


import java.io.Serializable;
class Model2 implements Serializable {
    int height;
}
public class CloneModel implements Serializable {
    private String name;
    private int age;
    private Model2 model2;
    public CloneModel() {
        this.model2 = new Model2();
    }
    public Model2 getModel2() {
        return model2;
    }
}

测试代码


import com.yangfei.test.CloneModel;
import java.io.*;
public class YfTest {
    public static <T extends Serializable> T deepCloneObject(T object) throws IOException {
        T deepClone = null;
        ObjectInputStream ois = null;
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
        )
        {
            oos.writeObject(object);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos
                    .toByteArray());
            ois = new ObjectInputStream(bais);
            deepClone = (T)ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null){
                ois.close();
            }
        }
        return deepClone;
    }
    public static void main(String[] args) throws IOException {
        CloneModel cloneModel1 = new CloneModel();
        CloneModel cloneModel2 = deepCloneObject(cloneModel1);
        System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
    }
}

输出


false

(2)其他序列化方式,如对象序列化json字符串再反序列化为对象

我们使用google的gson来进行序列化,上代码    


import com.google.gson.Gson;
import java.io.Serializable;
class Model2 implements Serializable {
    int height;
}
public class CloneModel implements Serializable {
    private String name;
    private int age;
    private Model2 model2;
    public CloneModel() {
        this.model2 = new Model2();
    }
    public Model2 getModel2() {
        return model2;
    }
    public CloneModel deepClone() {
        Gson gson = new Gson();
        return gson.fromJson(gson.toJson(this), CloneModel.class);
    }
}

测试代码


public static void main(String[] args) throws IOException {
    CloneModel cloneModel1 = new CloneModel();
    CloneModel cloneModel2 = cloneModel1.deepClone();
    System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
}

输出


false

(3)性能对比测试

上代码

public static void main(String[] args) throws IOException {
    CloneModel cloneModel1 = new CloneModel();
    long time1 = System.currentTimeMillis();
    for(int i=0;i<1000;i++){
    // CloneModel cloneModel2 = cloneModel1.deepClone();
        CloneModel cloneModel2 = deepCloneObject(cloneModel1);
    }
    long time2 = System.currentTimeMillis();
    System.out.println((time2-time1)+"ms");
}

image.png

目录
相关文章
|
2月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
6天前
|
存储 Java 索引
Java快速入门之数组、方法
### Java快速入门之数组与方法简介 #### 一、数组 数组是一种容器,用于存储同种数据类型的多个值。定义数组时需指定数据类型,如`int[]`只能存储整数。数组的初始化分为静态和动态两种: - **静态初始化**:直接指定元素,系统自动计算长度,如`int[] arr = {1, 2, 3};` - **动态初始化**:手动指定长度,系统给定默认值,如`int[] arr = new int[3];` 数组访问通过索引完成,索引从0开始,最大索引为`数组.length - 1`。遍历数组常用`for`循环。常见操作包括求和、找最值、统计特定条件元素等。
|
2天前
|
Java
Java快速入门之类、对象、方法
本文简要介绍了Java快速入门中的类、对象和方法。首先,解释了类和对象的概念,类是对象的抽象,对象是类的具体实例。接着,阐述了类的定义和组成,包括属性和行为,并展示了如何创建和使用对象。然后,讨论了成员变量与局部变量的区别,强调了封装的重要性,通过`private`关键字隐藏数据并提供`get/set`方法访问。最后,介绍了构造方法的定义和重载,以及标准类的制作规范,帮助初学者理解如何构建完整的Java类。
|
3天前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
36 12
|
4天前
|
算法 Java API
Java 方法注释:规范、实用和高质量的写法
本文深入探讨了如何编写高质量的 Java 方法注释
26 11
|
4天前
|
SQL Java 数据库连接
【潜意识Java】Java中JDBC过时方法的替代方案以及JDBC为什么过时详细分析
本文介绍了JDBC中一些常见过时方法及其替代方案。
22 5
|
2月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
176 57
|
2月前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
98 38
|
1月前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
1月前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
54 6