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 ...
随机推荐
- ARTS-3
ARTS的初衷 Algorithm:主要是为了编程训练和学习.每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard).进行编程训练,如果不训练你看再多的算法 ...
- linux系统中不小心执行了rm -rf ./* 怎么办?解决:文件系统的备份与恢复
XFS提供了 xfsdump 和 xfsrestore 工具协助备份XFS文件系统中的数据.xfsdump 按inode顺序备份一个XFS文件系统.centos7选择xfs格式作为默认文件系统,而且不 ...
- android app开发中的常用组件
1 Activity 1.1 Activity的启动 第一,android manifest中指定的主activity,点击app的icon启动进入. 第二,使用intent,在另外一个activit ...
- 56 道高频 JavaScript 与 ES6+ 的面试题及答案
56 道高频 JavaScript 与 ES6+ 的面试题及答案 :https://segmentfault.com/a/1190000020082089?utm_source=weekly& ...
- 有序无序Ul->Li Ol->Li菜单,默认点击当前弹出下拉,再次点击收起下拉菜单(变形2 ---修饰)
从上面可以看出,两个问题,第一:下拉出现的太快太突然,第二:再点击下一个下拉菜单的时候,上一个不会闭合,针对这两个问题,接下来会一 一解决. 解决下拉太快: js中有个jquery效果,有一个效果是j ...
- stdcall 函数调用过程(以delphi为例),还有负数的补码
以delphi下调用stdcall 函数为例,从右往左压栈:procedure TForm1.Button2Click(Sender: TObject);var i:integer;begin i:= ...
- js实现404页面倒计时跳转
<script type="text/javascript"> (function(){ var i=5,timer=null,number=document.getE ...
- Paper Reading_Database
最近(以及预感接下来的一年)会读很多很多的paper......不如开个帖子记录一下读paper心得 AI+DB A. Pavlo et al., Self-Driving Database Engi ...
- onehot编码解释
什么是One-Hot编码? One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效. One-Hot编码是分类变 ...
- 在JSP中<%= >,<%! %>,<% %>所代表的含义
<%! %>:是jsp中的声明标签,通常声明全局变量,常量,方法等. <% %>:<% java代码 %>,其中可以包含局部变量,java语句等. <%= % ...