java浅克隆和深克隆,序列化和反序列化实现深克隆(封装序列化和反序列化操作)
本篇博客内容:
一、浅克隆(ShallowClone)和深克隆(DeepClone)
ObjectOutputStream + 内存流ByteArrayOutputStream
ObjectOutputStream + FileOutputStream
一、浅克隆(ShallowClone)和深克隆(DeepClone) <=返回目录
1.1、浅克隆和深克隆区别
package com.oy.shallowclone; /*
浅克隆(ShallowClone)和深克隆(DeepClone)。 在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,
值类型包括int、double、byte、boolean、char等简单数据类型,
引用类型包括类、接口、数组等复杂类型。
浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。 实现clone方法的步骤
(1)实现Cloneable接口
(2)重写Object类中的clone()方法,重写时需定义为public
(3)在重写方法中,调用super.clone()
*/
public class Student implements Cloneable {
private int number; public int getNumber() {
return number;
} public void setNumber(int number) {
this.number = number;
} @Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
} /*
@Override
public Object clone() {
Student stu = null;
try {
stu = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
*/
}
测试
package com.oy.shallowclone; public class StudentTest {
public static void main(String args[]) throws CloneNotSupportedException {
Student stu1 = new Student();
stu1.setNumber(12345); // stu1克隆出stu2
Student stu2 = (Student) stu1.clone(); System.out.println("学生1:" + stu1.getNumber()); //
System.out.println("学生2:" + stu2.getNumber()); // stu2.setNumber(54321); // 修改stu2 System.out.println("学生1:" + stu1.getNumber()); //
System.out.println("学生2:" + stu2.getNumber()); //
}
}
1.2、浅克隆
Cat类
package com.oy.shallowclone; public class Cat implements Cloneable {
private String name;
// getter和setter省略 @Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Person类
package com.oy.shallowclone; public class Person implements Cloneable {
private String name;
private Integer age;
private Cat cat;
// getter和setter省略 @Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类
package com.oy.shallowclone; public class PersonTest {
public static void main(String[] args) throws CloneNotSupportedException {
Cat cat = new Cat();
cat.setName("狸花"); Person per1 = new Person();
per1.setName("张三");
per1.setAge(10);
per1.setCat(cat); // per1克隆出per2
Person per2 = (Person) per1.clone(); System.out.println(per1.getName() + "-" + per1.getAge() + "-" + per1.getCat().getName()); // 张三-10-狸花
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); // 张三-10-狸花
System.out.println(per1.getName() == per2.getName()); // true
System.out.println(per1.getAge() == per2.getAge()); // true
System.out.println(per1.getCat() == per1.getCat()); // true // 修改per1
per1.setName("李四"); // per1的name属性保存另一个"字符串"的地址
per1.setAge(20);
cat.setName("小橘"); System.out.println(per1.getName() + "-" + per1.getAge() + "-" + per1.getCat().getName()); // 李四-20-小橘
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); // 张三-10-小橘
System.out.println(per1.getName() == per2.getName()); // false
System.out.println(per1.getAge() == per2.getAge()); // false
System.out.println(per1.getCat() == per1.getCat()); // true
}
}
理论上String和Integer类型的属性的克隆也是浅克隆。但是,String和Integer是不可变的。所以,实际上当String和Integer类型的属性改变时,克隆对象不会跟着改变。
package com.oy.shallowclone; /**
* 理论上String和Integer类型的属性的克隆也是浅克隆。
* 但是,String和Integer是不可变的。所以,实际上当String和Integer类型的属性改变时,克隆对象不会跟着改变。
*
* @author oy
*/
public class PersonTest2 {
public static void main(String[] args) throws CloneNotSupportedException {
Cat cat = new Cat();
cat.setName("狸花"); Person per1 = new Person();
String name = new String("张三");
per1.setName(name);
Integer age = new Integer("10");
per1.setAge(age);
per1.setCat(cat); // per1克隆出per2
Person per2 = (Person) per1.clone(); System.out.println(per1.getName() + "-" + per1.getAge() + "-" + per1.getCat().getName()); // 张三-10-狸花
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); // 张三-10-狸花
System.out.println(per1.getName() == per2.getName()); // true 说明是浅克隆
System.out.println(per1.getAge() == per2.getAge()); // true 说明是浅克隆
System.out.println(per1.getCat() == per1.getCat()); // true 说明是浅克隆 // 修改per1
name = new String("李四"); // 只是修改了name变量里面保存的地址值
age = new Integer("20"); // 只是修改了age变量里面保存的地址值
cat.setName("小橘"); System.out.println(per1.getName() + "-" + per1.getAge() + "-" + per1.getCat().getName()); // 张三-10-小橘
System.out.println(per2.getName() + "-" + per2.getAge() + "-" + per2.getCat().getName()); // 张三-10-小橘
System.out.println(per1.getName() == per2.getName()); // true
System.out.println(per1.getAge() == per2.getAge()); // true
System.out.println(per1.getCat() == per1.getCat()); // true
}
}
1.3、深克隆
Teacher类
package com.oy.deepclone; class Teacher implements Cloneable {
private int age;
private String name; // getter和setter省略 @Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Student类
package com.oy.deepclone; public class Student implements Cloneable {
private int age;
private String name;
private Teacher teacher; // getter和setter省略 @Override
public Object clone() throws CloneNotSupportedException {
// 这一步返回的这个student还只是一个浅克隆,
Student student = (Student) super.clone();
// 然后克隆的过程中获得这个克隆的student,然后调用这个getTeacher这个方方法得到这个Teacher对象。
// 然后实现克隆。在设置到这个student中的Teacher。
// 这样实现了双层克隆使得那个teacher对象也得到了复制。
student.setTeacher((Teacher) student.getTeacher().clone());
// 双层克隆使得那个teacher对象也得到了复制
return student;
}
}
测试类
package com.oy.deepclone; public class Test { public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setAge(40);
teacher.setName("teacher zhang"); Student stu1 = new Student();
stu1.setAge(10);
stu1.setName("张三");
stu1.setTeacher(teacher); //stu1深克隆出stu2
Student stu2 = (Student) stu1.clone(); // 这里是深复制,所以这时候Student中的teacher就是teacher这个对象的一个复制,就和student2是Student的一个复制
// 所以下面teacher.setName只是对他原来的这个对象更改,但是复制的那个并没有更改
System.out.println(stu1.getName() + "-" + stu1.getAge() + "-" + stu1.getTeacher().getName());//张三-10-teacher zhang
System.out.println(stu2.getName() + "-" + stu2.getAge() + "-" + stu2.getTeacher().getName());//张三-10-teacher zhang // 修改stu1
stu1.setName("李四");
stu1.setAge(20);
teacher.setName("teacher wang"); System.out.println(stu1.getName() + "-" + stu1.getAge() + "-" + stu1.getTeacher().getName());//李四-20-teacher wang
System.out.println(stu2.getName() + "-" + stu2.getAge() + "-" + stu2.getTeacher().getName());//张三-10-teacher zhang
}
}
二、序列化和反序列化实现深克隆 <=返回目录
Car类
public class Car implements Serializable {
private static final long serialVersionUID = -7633040136520448512L;
private String name;
private String color; public Car() {} public Car(String name, String color) {
this.name = name;
this.color = color;
} // getter和setter方法省略 @Override
public String toString() {
return "Car [name=" + name + ", color=" + color + "]";
}
}
Person类
public class Person implements Serializable {
private static final long serialVersionUID = 4792126594710124401L;
private String name;
private int age;
private Car car; public Person() {} public Person(String name, int age) {
this.name = name;
this.age = age;
} public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
} // getter和setter方法省略 @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
工具类:使用序列化和反序列化实现对象的克隆
package com.oy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; /**
* 工具类:使用序列化和反序列化实现对象的克隆
*
* @author oy
* @version 1.0
* @date 2018年8月9日
* @time 下午8:59:23
*/
public class cloneUtil {
private cloneUtil() {
} @SuppressWarnings("unchecked")
public static <T extends Serializable> T cloneObject(T obj) {
T cloneObj = null; // 序列化
ByteArrayOutputStream bout = null;
ObjectOutputStream oos = null;
try {
bout = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
} finally {
close(oos);
close(bout);
} // 反序列化
ByteArrayInputStream bin = null;
ObjectInputStream ois = null;
try {
bin = new ByteArrayInputStream(bout.toByteArray());
ois = new ObjectInputStream(bin);
cloneObj = (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
close(ois);
close(bin);
} return cloneObj;
} private static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试
/**
* 序列化和反序列化实现深克隆
*
* @author oy
* @version 1.0
* @date 2018年8月9日
* @time 下午8:58:53
*/
public class Test {
public static void main(String[] args) {
Car car = new Car("BYD", "black");
Person p1 = new Person("张三", 20, car);
Person p2 = cloneUtil.cloneObject(p1); System.out.println("P1:" + p1);//P1:Person [name=张三, age=20, car=Car [name=BYD, color=black]]
System.out.println("p2:" + p2);//p2:Person [name=张三, age=20, car=Car [name=BYD, color=black]] if (p2 != null) {
car.setName("宝马");
car.setColor("red");
} System.out.println("P1:" + p1);//P1:Person [name=张三, age=20, car=Car [name=宝马, color=red]]
System.out.println("p2:" + p2);//p2:Person [name=张三, age=20, car=Car [name=BYD, color=black]]
}
}
三、封装序列化和反序列化操作 <=返回目录
3.1、封装序列化和反序列化操作
package com.oy; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List; /**
* 序列化,反序列化工具类。用于转换byte[]和对象
*
* @author oy
* @date 2019年6月3日 下午11:46:53
* @version 1.0.0
*/
public class SerializeUtil { public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
e.printStackTrace();
} finally {
close(oos);
close(baos);
}
return null;
} public static Object unserialize(byte[] bytes) {
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(bais);
close(ois);
}
return null;
} /**
* 序列化 list 集合
*
* @param list
* @return
*/
public static byte[] serializeList(List<?> list) { if (list == null || list.size() <= 0) {
return null;
}
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
byte[] bytes = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
for (Object obj : list) {
oos.writeObject(obj);
}
bytes = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(oos);
close(baos);
}
return bytes;
} /**
* 反序列化 list 集合
*
* @param lb
* @return
*/
public static List<?> unserializeList(byte[] bytes) {
if (bytes == null) {
return null;
} List<Object> list = new ArrayList<Object>();
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
while (bais.available() > 0) {
Object obj = (Object) ois.readObject();
if (obj == null) {
break;
}
list.add(obj);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close(bais);
close(ois);
}
return list;
} /**
* 关闭io流对象
*
* @param closeable
*/
public static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
3.2、cloneUtil类改为:
public class cloneUtil {
private cloneUtil() {} @SuppressWarnings("unchecked")
public static <T extends Serializable> T cloneObject(T obj) {
// 序列化
byte[] bs = SerializeUtil.serialize(obj); // 反序列化
return (T) SerializeUtil.unserialize(bs);
}
}
四、对象持久化到文件或从文件中读取对象 <=返回目录
package com.oy; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; /**
* 序列化和反序列化
*
* @author oy
* @version 1.0
* @date 2018年8月9日
* @time 下午8:58:32
*/
public class serialDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建Person对象
Car car = new Car("BMW", "black");
Person p = new Person("张三abc", 20, car); write(p);
Object obj = read(); // Person [name=张三abc, age=20, car=Car [name=BMW, color=black]]
System.out.println(obj); } private static Object read() throws FileNotFoundException, IOException, ClassNotFoundException {
// 创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\object.txt"));
// 反序列化
Object obj = ois.readObject();
// 释放资源
ois.close();
return obj;
} private static void write(Object obj) throws FileNotFoundException, IOException {
// 创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));
// 序列化
oos.writeObject(obj);
// 释放资源
oos.close();
}
}
参考:
(2)Java基础学习总结——Java对象的序列化和反序列化
java浅克隆和深克隆,序列化和反序列化实现深克隆(封装序列化和反序列化操作)的更多相关文章
- Java序列化的几种方式以及序列化的作用
Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用 有的时候我们想要把一个Java对象 ...
- java中POJO类和DTO类都要实现序列化
java中POJO类和DTO类都要实现序列化 java中POJO类和DTO类都要实现序列化 java中POJO类和DTO类都要实现序列化 序列化:序列化是将对象转换为容易传输的格式的过程.例如,可以序 ...
- Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题【转】
Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题 http://blog.didispace.com/Spring-Boot-And-Feign- ...
- c#序列化感悟(重点讲讲二进制序列化)
序列化是一种通过将对象转化为字节流,从而达到储存对象,或者将对象传输到内存,数据库或文件的一个过程,主要用途是保存对象的状态(包括对象的数据),方便对对象的重建,反之读取就是反序列化. 三种序列化类型 ...
- [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java.io下的方法是对磁盘上的文件进行磁盘操作
File类(java.io.*)可表示一个文件,也有可能是一个目录(在JAVA中文件和目录都属于这个类中,而且区分不是非常的明显). Java.io下的方法是对磁盘上的文件进行磁盘操作,但是无法读取文 ...
- Java基础知识强化之IO流笔记65:序列化流 和 反序列化流
1. 什么是 序列化 和 反序列化 ? 序列化 (Serialization):将对象的状态信息转换为可以存储或传输的形式的过程.比如转化为二进制.xml.json等的过程. 在序列化期间,对 ...
- java 浅克隆 深克隆
对象的克隆是java的一项高级技术,他可以根据给定的对象,获得与其完全相同的另一个对象. 1.浅克隆主要是复制对象的值 2.深克隆:当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆,可以复制引用类 ...
- java 浅克隆(浅复制)和深克隆(深复制)
http://www.voidcn.com/blog/u011380813/article/p-6161450.html https://gold.xitu.io/entry/570d89651ea4 ...
随机推荐
- IDE引入mindmap插件,在项目中添加思维导图
1.打开IDE,file--settings--plugins,搜索IDEA Mind Map 2.点击install,进行下载,然后按照提示restart重启IDEA,安装完成 3.创建mind m ...
- Android专项测试监控资源
版本号 V 1.1.0 Android性能测试分为两类:1.一类为rom版本(系统)的性能测试2.一类为应用app的性能测试(本次主要关注点为app的性能测试) Android的app性能测试包括的测 ...
- 深入理解java:2.3.1. 并发编程concurrent包 之Atomic原子操作(循环CAS)
java中,可能有一些场景,操作非常简单,但是容易存在并发问题,比如i++, 此时,如果依赖锁机制,可能带来性能损耗等问题, 于是,如何更加简单的实现原子性操作,就成为java中需要面对的一个问题. ...
- python下对文件的操作(非目录)
总文件夹 子文件夹01 文档01.txt-------------------------------------------------------------------------------- ...
- Springboot+Jedis+Ehcache整合
项目结构概览: 1. 导包 <parent> <groupId>org.springframework.boot</groupId> <artifactId& ...
- go & cron
https://github.com/robfig/cron - 源码 cron - GoDoc 参考 go---定时任务 cron,gin 静态文件 go语言里比较好用的计划任务调度模块
- There are multiple modules with names that only differ in casing. This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
There are multiple modules with names that only differ in casing.This can lead to unexpected behavio ...
- SEM和SEO的区别?
https://www.zhihu.com/question/20307058 SEM在营销中扮演的角色:进攻 搜索引擎营销,即SEM(Search Engine Marketing),是基于搜索引擎 ...
- 基于Nginx+nginx-rtmp-module+ffmpeg搭建rtmp、hls流媒体服务器(二)
前言 Nginx-rtmp-module插件针对RTMP协议中一些命令,实现了事件通知和exec外部脚本处理.这里我通过一个简单的SpringBoot项目和Python代码,快速搭建一个HTTP服务来 ...
- man - 格式化并显示在线帮助手册页
总览 man [-acdfFhkKtwW] [-m 系统名] [-p <前处理程序>] [-C <配置文件>] [-M <路径>] [-P <浏览方式> ...