JAVA高级技术-对象克隆(几种深克隆效率比较)

回城传送–》《JAVA筑基100例》

文章目录

  • 一、题目描述
  • 二、解题思路-序列化克隆
  • 三、代码详解
    • 原生序列化和Kryo序列化性能比较
    • 结论
  • 四、推荐专栏

一、题目描述

题目:对象的克隆是Java一项高级技术,可以根据给定的对象,获得与其完全相同的另一个对象。

前面介绍了三种实现深克隆的方式,现在对这三种方式克隆10万个对象,并输出花费的时间。这样大家就可以有个直观的认识。

二、解题思路-序列化克隆

再创建一个员工类Employee

定义三个成员变量表示:员工名字,年龄

使用构造方法对它们进行赋值。

并提供对应的get方法和set方法。

重写toString()方法和clone()方法。

三、代码详解

员工类:

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();}@Overridepublic String toString() {// 重写toString()方法StringBuilder sb = new StringBuilder();sb.append("姓名:" + name + ", ");sb.append("年龄:" + age + "\n");return sb.toString();}@Overrideprotected Employee clone() {// 使用父类的clone()方法实现深克隆Employee employee = null;try {employee = (Employee) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return employee;}
}

测试类

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) + "毫秒");}
}

如图

原生序列化和Kryo序列化性能比较

原生序列化:

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** 
* 修改记录:* 修改后版本	        修改人		修改日期			修改内容* 2022/5/20.1	    xiaoxuzhu		2022/5/20		    Create* 
* @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序列化:

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** 
* 修改记录:* 修改后版本	        修改人		修改日期			修改内容* 2022/5/20.1	    xiaoxuzhu		2022/5/20		    Create* 
* @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();}}}}

10万条测试结果:

java原生序列化时间:2762 ms
java原生反序列化时间:3405 ms

Kryo 序列化时间:575 ms
Kryo 反序列化时间:156 ms

Kryo 的性能是原生的序列化性能二十几倍。

结论

1、使用clone方法克隆(不实用):

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

2、使用原生序列化克隆(不实用):

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

3、使用第三方工具方法 BeanUtils.copyProperties,克隆时间适中:

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

4、使用Kryo 序列化效果比用原生序列化好

企业级应用开发中:

  • 简单的对象克隆(浅克隆),可以用 BeanUtils.copyProperties

  • 复杂对象的序列化克隆,可以用Kryo 序列化处理。

四、推荐专栏

《JAVA从零到壹》

《JAVA从零到壹》第四讲:类与对象基础

第六讲:数组包及访问控制

《JAVA从零到壹》第七讲:面向对象高级特性


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部