JAVA advanced technology - object cloning (comparison of several deep cloning efficiencies)

Teleportation back to the city – " 100 cases of JAVA foundation building"

1. Topic description

Topic: Object cloning is an advanced technology in Java, which can obtain another object that is exactly the same as it is based on a given object.

Three ways to implement deep cloning were introduced earlier, and now 100,000 objects are cloned for these three ways, and the time spent is output. In this way, everyone can have an intuitive understanding.

2. Problem-solving ideas-serialized cloning

Create another employee class Employee

Define three member variables to represent: employee name, age

Use constructors to assign values ​​to them.

And provide the corresponding get method and set method.

Override the toString() method and the clone() method.

3. Detailed Code Explanation

Employee class:

public class Employee implements Cloneable, Serializable {
    
    
    private static final long serialVersionUID = 5022956767440380940L;
    private String name; // 表示员工的姓名
    private int age; // 表示员工的年龄

    public Employee(String name, int age) {
    
    // 利用构造方法初始化各个域
        this.name = name;
        this.age = age;
    }

    public Employee() {
    
    // 利用构造方法初始化各个域
        super();
    }

    @Override
    public String toString() {
    
    // 重写toString()方法
        StringBuilder sb = new StringBuilder();
        sb.append("姓名:" + name + ", ");
        sb.append("年龄:" + age + "\n");
        return sb.toString();
    }

    @Override
    protected Employee clone() {
    
    // 使用父类的clone()方法实现深克隆
        Employee employee = null;
        try {
    
    
            employee = (Employee) super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            e.printStackTrace();
        }
        return employee;
    }
}

test class

public class Test {
    
    

    public static void main(String[] args) {
    
    
        List<Employee> employees = new ArrayList<Employee>();// 创建列表保存对象
        Employee employee = new Employee("小虚竹", 25);// 创建Employee类的对象
        long currentTime = System.currentTimeMillis();// 获得当前系统时间
        for (int i = 0; i < 100000; i++) {
    
    
            employees.add(employee.clone());// 使用克隆方式获得对象
        }
        System.out.println("clone()方法克隆花费时间:" + (System.currentTimeMillis() - currentTime) + "毫秒");
        currentTime = System.currentTimeMillis();// 获得当前时间

        for (int i = 0; i < 100000; i++) {
    
    
            ByteArrayOutputStream baos = new ByteArrayOutputStream();// 创建字节数组输出流
            ObjectOutputStream out = null;
            try {
    
    
                out = new ObjectOutputStream(baos);// 创建对象输出流
                out.writeObject(employee);// 将对象写入到输出流中
            } catch (IOException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                if (out != null) {
    
    
                    try {
    
    
                        out.close();// 释放资源
                    } catch (IOException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
            // 获得字节数组输出流内容
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream in = null;
            try {
    
    
                in = new ObjectInputStream(bais);// 创建对象输入流
                employees.add((Employee) in.readObject());// 读取对象
            } catch (IOException e) {
    
    
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                if (in != null) {
    
    
                    try {
    
    
                        in.close();// 释放资源
                    } catch (IOException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        }
        System.out.println("序列化花费时间:" + (System.currentTimeMillis() - currentTime) + "毫秒");
        currentTime = System.currentTimeMillis();// 获得当前时间
        
        for (int i = 0; i < 100000; i++) {
    
    
            Employee employee2 = new Employee();
            BeanUtils.copyProperties(employee,employee2);
        }
        System.out.println("BeanUtils.copyProperties花费时间:" + (System.currentTimeMillis() - currentTime) + "毫秒");
    }
}

as shown in the picture

Native serialization and Kryo serialization performance comparison

Native serialization:

package com.xiaoxuzhu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * Description: 原生序列化
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改记录:
 * 修改后版本	        修改人		修改日期			修改内容
 * 2022/5/20.1	    xiaoxuzhu		2022/5/20		    Create
 * </pre>
 * @date 2022/5/20
 */
public class OriginalSerializable {
    
    

    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        long start =  System.currentTimeMillis();
        setSerializableObject();
        System.out.println("java原生序列化时间:" + (System.currentTimeMillis() - start) + " ms" );
        start =  System.currentTimeMillis();
        getSerializableObject();
        System.out.println("java原生反序列化时间:" + (System.currentTimeMillis() - start) + " ms");
    }

    public static void setSerializableObject() throws IOException{
    
    

        FileOutputStream fo = new FileOutputStream("D:/file.bin");
        ObjectOutputStream so = new ObjectOutputStream(fo);
        Employee employee = null;
        for (int i = 0; i < 100000; i++) {
    
    
             employee = new Employee("小虚竹", 25);// 创建Employee类的对象
            so.writeObject(employee);
        }
        so.writeObject(null);//为了解决EOF异常
        so.flush();
        so.close();
    }

    public static void getSerializableObject(){
    
    
        FileInputStream fi;
        try {
    
    
            fi = new FileInputStream("D:/file.bin");
            ObjectInputStream si = new ObjectInputStream(fi);

            Employee employee =null;
            while((employee=(Employee)si.readObject()) != null){
    
    
            }
            fi.close();
            si.close();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();  
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }

    }
}

Kyro serialization:

package com.xiaoxuzhu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.objenesis.strategy.StdInstantiatorStrategy;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
 * Description: Kyro序列化
 *    kryo.KryoException: Buffer underflow.
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改记录:
 * 修改后版本	        修改人		修改日期			修改内容
 * 2022/5/20.1	    xiaoxuzhu		2022/5/20		    Create
 * </pre>
 * @date 2022/5/20
 */
public class KyroSerializable {
    
    
    public static void main(String[] args) throws IOException {
    
    
        long start =  System.currentTimeMillis();
        setSerializableObject();
        System.out.println("Kryo 序列化时间:" + (System.currentTimeMillis() - start) + " ms" );
        start =  System.currentTimeMillis();
        getSerializableObject();
        System.out.println("Kryo 反序列化时间:" + (System.currentTimeMillis() - start) + " ms");

    }

    public static void setSerializableObject() {
    
    
        Output output = null;
        try {
    
    
            Kryo kryo = new Kryo();
            kryo.setReferences(false);
            kryo.setRegistrationRequired(false);
            kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
            kryo.register(Employee.class);
             output = new Output(new FileOutputStream("D:/file1.bin"));
            Employee employee = null;
            for (int i = 0; i < 100000; i++) {
    
    
                employee = new Employee("小虚竹", 25);// 创建Employee类的对象
                kryo.writeObject(output, employee);
            }
            output.flush();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            if(output !=null){
    
    
                output.close();
            }
        }
    }


    public static void getSerializableObject(){
    
    
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.setRegistrationRequired(false);
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        Input input = null;
        try {
    
    
            input = new Input(new FileInputStream("D:/file1.bin"));
            Employee employee =null;
            while((employee=kryo.readObject(input, Employee.class)) != null){
    
    
            }
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch(KryoException e){
    
    
        }finally {
    
    
            if(input !=null){
    
    
                input.close();
            }
        }
    }

}

100,000 test results:

Java native serialization time: 2762 ms
Java native deserialization time: 3405 ms

Kryo serialization time: 575 ms
Kryo deserialization time: 156 ms

The performance of Kryo is more than twenty times that of native serialization.

in conclusion

1. Use the clone method to clone (not practical):

- 优点:最快的,10万条数据可以控制在100ms内
- 缺点:但这个的使用也是最麻烦的,类要重写clone方法,有引类类型的参数类也要重写clone方法

2. Use native serialization to clone (not practical):

- 优点:序列化不需要每个对象都重写clone方法,同时支持类里的引用类型参数的深克隆
- 缺点:花费的时间最长

3. Using the third-party tool method BeanUtils.copyProperties, the cloning time is moderate:

- 优点:使用简单方便
- 缺点:只能进行浅克隆,对于引用类型的参数是无法克隆的,只是复制引用,不是克隆值 ,所以要额外处理。

4. Using Kryo serialization is better than native serialization

In enterprise application development:

  • Simple object cloning (shallow cloning), you can use BeanUtils.copyProperties

  • Serialized cloning of complex objects can be serialized with Kryo.

4. Recommended column

"JAVA From Zero to One"

"JAVA From Zero to One" Lecture 4: Basics of Classes and Objects

Lecture 6: Array package and access control

"JAVA From Zero to One" Lecture Seven: Advanced Object-Oriented Features

Guess you like

Origin blog.csdn.net/shi_hong_fei_hei/article/details/131488447