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

目录
相关文章
|
4天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
31 17
|
2天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
1天前
|
Java
Java基础(13)抽象类、接口
本文介绍了Java面向对象编程中的抽象类和接口两个核心概念。抽象类不能被实例化,通常用于定义子类的通用方法和属性;接口则是完全抽象的类,允许声明一组方法但不实现它们。文章通过代码示例详细解析了抽象类和接口的定义及实现,并讨论了它们的区别和使用场景。
|
1天前
|
Java 测试技术 API
Java零基础-接口详解
【10月更文挑战第19天】Java零基础教学篇,手把手实践教学!
8 1
|
6天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
11 3
|
6天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
9 2
|
6天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
18 2
|
6天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
15 2
|
6天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
8 1
|
6天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
16 1