java序列化与深度拷贝

【README】

  • 1, 为啥要序列化或序列化的意义?
  • 2,系统间调用的报文格式,大多数是Json字符串(或字节数组);接收方接收json;
  • 3,但当系统调用如RMI,客户端请求服务器获取一个 javabean对象的状态信息,而不是json格式,这个时候 json格式就不合适了;当然了,在发送时我们可以 把 javabean的状态信息的属性转为json;接收时把json对象转为 javabean;很显然,这样太复杂了,而且不利于维护,一旦 javabean的属性做修改,需要改的代码太多
  • 4,基于此, 序列化出现了,序列化可以把对象信息转换为字节数组,保存到媒介中(如磁盘,内存,或传输到网络),后续需要用到的时候,可以直接把字节数组反序列化为java对象,而不需要做其他操作;也可以理解为是 java对象持久化
    • 这可以解决 系统调用间 javabean对象信息传输的问题;即请求前,把对象序列化为字节数组;接收时,把字节数组反序列化(直接解析)为java bean对象(而不需要其他格式转换);
  • 5,序列化的另一个用途是 用于java对象的深拷贝

【补充1】本文给出了3种实现序列化的方式,包括

  • 1种自动方式(实现 Serializable 接口);
  • 2种手动方式(分别实现 Externalizable, Serializable 接口);

【补充2】自动实现与手动实现

  • 自动实现: 程序员无需自定义字段序列化策略,由 java底层默认实现;
  • 手动实现:程序员需要自定义自定序列化策略,哪些需要序列化,哪些不需要;

【1】java序列化实现

1)java序列化定义: 把那些实现了 Serializable 接口的对象转换成一个字节序列;并能够在以后把这个字节 序列完全恢复到原来的对象;实现对 javabean状态的持久化

2)如何理解持久性? 持久性意味着一个对象的生命周期并不取决于 程序是否在执行;就像数据库的持久化一样;但一个对象可以存在于 程序的调用之间,如远程方法调用 RMI;

3)通过序列化可以把java对象以字节格式保存到磁盘,内存,网络流上面;在以后需要的时候,把序列化后的字节恢复(或反序列化)成原来的 javabean的状态;


【2】 序列化实现

【2.1】实现 Serializable 接口自动实现序列化

 javabean序列化

/*** @Description 实现Serializable自动实现序列化与反序列化* @author xiao tang* @version 1.0.0* @createTime 2021年11月20日*/
public class AutoSerializableClass implements Serializable {String name;Date date;Map<String, String> configs;// transient 表示不序列化agetransient int age;public AutoSerializableClass(String name) {this(name, Collections.emptyMap(), new Date(), 18);}public AutoSerializableClass(String name, Map<String, String> configs) {this(name, configs, new Date(), 18);}public AutoSerializableClass(String name, Map<String, String> configs, Date date, int age) {this.name = name;this.configs = configs;this.date = date;this.age = age;}public String getName() {return name;}public Map<String, String> getConfigs() {return configs;}/*** @description 基于序列化的深度拷贝* @return AutoSerializableClass* @author xiao tang* @date 2021/11/20*/public AutoSerializableClass deepClone() throws Exception {ByteArrayOutputStream buf = new ByteArrayOutputStream();// 把流放在 tyr资源块中,程序结束java会自动关闭流资源try (ObjectOutputStream outputStream = new ObjectOutputStream(buf)) {outputStream.writeObject(this);}try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()))) {return (AutoSerializableClass) inputStream.readObject();}} @Overridepublic String toString() {return "AutoSerializableClass{" +"name='" + name + '\'' +", date=" + date +", configs=" + configs +", age=" + age +'}';}
}

【2.1.1】序列化到磁盘与反序列

public static String path = "d://temp//"; 
/*** @description 测试用例-把 AutoSerializableClass 对象序列化到磁盘* @author xiao tang* @date 2021/11/20*/public static void main(String[] args) throws IOException, ClassNotFoundException {// 把 AutoSerializableClass 对象序列化到磁盘ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(path + "my01.out"));outputStream.writeObject(new AutoSerializableClass("zhangsan"));outputStream.close();// 从磁盘读取序列化对象ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path + "my01.out"));AutoSerializableClass objParsed = (AutoSerializableClass) objectInputStream.readObject();System.out.println(objParsed.getName()); // zhangsan}

【2.1.2】深度拷贝

/** * @description 测试用例-基于 Serializable接口自动实现序列化的深度拷贝* @author xiao tang* @date 2021/11/20 */public static void main(String[] args) throws Exception {Map<String, String> configs = new HashMap<>();configs.put("k1", "v1");AutoSerializableClass lisi = new AutoSerializableClass("lisi", configs);// 深度拷贝到lisi2 和 lisi3AutoSerializableClass lisi2 = lisi.deepClone();AutoSerializableClass lisi3 = lisi.deepClone();// 为lisi2添加配置lisi2.getConfigs().put("k2", "v2");System.out.println("\n lisi2==="); // configs={k1=v1, k2=v2}, age=0System.out.println(lisi2);System.out.println("\n lisi3==="); // configs={k1=v1}, age=0System.out.println(lisi3);// 为lisi3添加配置lisi3.getConfigs().put("k3", "v3");System.out.println("\n lisi2==="); // configs={k1=v1, k2=v2}, age=0System.out.println(lisi2);System.out.println("\n lisi3==="); // configs={k1=v1, k3=v3}, age=0 System.out.println(lisi3);}

 lisi2===
AutoSerializableClass{name='lisi', date=Sat Nov 20 21:43:50 CST 2021, configs={k1=v1, k2=v2}, age=0}

 lisi3===
AutoSerializableClass{name='lisi', date=Sat Nov 20 21:43:50 CST 2021, configs={k1=v1}, age=0}

 lisi2===
AutoSerializableClass{name='lisi', date=Sat Nov 20 21:43:50 CST 2021, configs={k1=v1, k2=v2}, age=0}

 lisi3===
AutoSerializableClass{name='lisi', date=Sat Nov 20 21:43:50 CST 2021, configs={k1=v1, k3=v3}, age=0}

【代码解说】

  • 1,可以看到  lisi2 lisi3 是独立的两个对象,且反序列化后,lisi2,lisi3 定义的 configs 不是同一个 ;
  • 2,age 本身初始化为18,但这里为0,是因为 age 被修改为 transient,表示不序列该字段,故age取int默认值0;
  • 3,接口 Serializable 没有任何方法,仅一个标识接口而已;

【2.2】实现  Externalizable 接口手动实现序列化

1,Externalizable接口继承自  Serializable, 有2个方法需要实现;

2,这两个方法 writeExternal 和 readExternal 方法 会分别在序列化和反序列化还原的过程中被自动调用,以便执行一些特殊操作(对某些字段进行序列化与反序列化,某些不进行如账号密码,private字段不序列化等) ;如 我们可以对age 字段进行序列化和反序列化,即便age被 transient 修饰

public interface Externalizable extends java.io.Serializable {void writeExternal(ObjectOutput out) throws IOException;   void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

3,Externalizable 实现类

/*** @Description 实现Externalizable手动实现序列化与反序列化* @author xiao tang* @version 1.0.0* @createTime 2021年11月20日*/
public class ManualExternalizableClass implements Externalizable {String name;Date date;Map<String, String> configs;// transient 表示不序列化agetransient int age;public ManualExternalizableClass(){}public ManualExternalizableClass(String name) {this(name, new Date(), new HashMap<String, String>(), 18);}public ManualExternalizableClass(String name, Date date, Map<String, String> configs, int age) {this.name = name;this.date = date;this.configs = configs;this.age = age;}/** * @description 序列化过程自动调用* @param out 序列化书写流* @author xiao tang* @date 2021/11/20 */@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(name);out.writeObject(date);out.writeInt(age);}/** * @description 反序列化过程自动调用* @param in 反序列化读入流* @author xiao tang* @date 2021/11/20 */@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {this.name = String.valueOf(in.readObject());this.date = (Date) in.readObject();this.age = in.readInt();}/*** @description 深度拷贝 ManualExternalizableClass* @return MyExternalizableClass对象* @author xiao tang* @date 2021/11/20*/public ManualExternalizableClass deepClone() throws Exception {ByteArrayOutputStream buf = new ByteArrayOutputStream();try (ObjectOutputStream outputStream = new ObjectOutputStream(buf)) {outputStream.writeObject(this);}try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()))) {return (ManualExternalizableClass) inputStream.readObject();}}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "ManualExternalizableClass{" +"name='" + name + '\'' +", date=" + date +", configs=" + configs +", age=" + age +'}';}
}

【2.2.1】 测试用例,对 Externalizable 对象进行深拷贝

/*** @Description 测试用例-实现Externalizable手动实现序列化与反序列化* @author xiao tang* @version 1.0.0* @createTime 2021年11月20日*/
public class ManualExternalizableClassTest {public static void main(String[] args) throws Exception {ManualExternalizableClass obj = new ManualExternalizableClass("zhangsan");// 深度拷贝ManualExternalizableClass newObj = obj.deepClone();newObj.setAge(19); // 对新对象的age赋值,不影响老对象System.out.println("obj = " + obj); // age=18System.out.println("newObj = " + newObj); // age=19}
}

obj = MyExternalizableClass{name='zhangsan', date=Sat Nov 20 20:32:15 CST 2021, configs={}, age=18}
newObj = MyExternalizableClass{name='zhangsan', date=Sat Nov 20 20:32:15 CST 2021, configs=null, age=19}

【代码解说】

  • 1,上述javabean MyExternalizableClass实现了 Externalizable 接口的方法 writeExternal() ,序列化字段name,date, age;实现了方法 readExternal(),反序列化字段 name, date, age;即便age 被 transient 修饰,但我们还可以序列化;
  • 2,这种方式的序列化,需要指定序列化的字段,本文定义为 手动序列化方式

【2.3】实现Serializable手动实现序列化

1)序列化javabean

/*** @Description 实现 Serializable 手动实现序列化与反序列化* @author xiao tang* @version 1.0.0* @createTime 2021年11月20日*/
public class ManualSerializableClass implements Serializable {String name;Date date;Map<String, String> configs;// transient 表示不序列化agetransient int age;public ManualSerializableClass(String name) {this(name, new HashMap<>(), new Date(), 18);}public ManualSerializableClass(String name, Map<String, String> configs) {this(name, configs, new Date(), 18);}public ManualSerializableClass(String name, Map<String, String> configs, Date date, int age) {this.name = name;this.configs = configs;this.date = date;this.age = age;}public String getName() {return name;}public Map<String, String> getConfigs() {return configs;}/** * @description 序列化过程自动调用(注意这里并不是重写 Serializable接口方法,即便没有重写,序列化过程也会自动调用,算是java一个缺陷,from thingking-in-java)* @param outputStream 书写流* @author xiao tang* @date 2021/11/20 */private void writeObject(ObjectOutputStream outputStream) throws IOException {outputStream.defaultWriteObject(); // 先调用默认序列化方式outputStream.writeInt(age); // 把age 进行手动序列化}/** * @description 反序列化过程自动调用(注意这里并不是重写 Serializable接口方法,即便没有重写,反序列化过程也会自动调用,算是java一个缺陷,from thingking-in-java)* @param inputStream 读入流* @author xiao tang* @date 2021/11/20 */private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {inputStream.defaultReadObject(); // 先调用默认反序列化方式age = inputStream.readInt(); // 把 age 手动反序列化}/*** @description 基于序列化的深度拷贝* @return AutoSerializableClass* @author xiao tang* @date 2021/11/20*/public ManualSerializableClass deepClone() throws Exception {ByteArrayOutputStream buf = new ByteArrayOutputStream();try (ObjectOutputStream outputStream = new ObjectOutputStream(buf)) {outputStream.writeObject(this);}try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()))) {return (ManualSerializableClass) inputStream.readObject();}}@Overridepublic String toString() {return "AutoSerializableClass{" +"name='" + name + '\'' +", date=" + date +", configs=" + configs +", age=" + age +'}';}
}

2)测试用例

/*** @Description 测试用例-实现 Serializable 手动实现序列化与反序列化* @author xiao tang* @version 1.0.0* @createTime 2021年11月20日*/
public class ManualSerializableClassTest {public static void main(String[] args) throws Exception {ManualSerializableClass oldObj = new ManualSerializableClass("zhangsan");ManualSerializableClass newObj = oldObj.deepClone();newObj.getConfigs().put("newK", "newV");System.out.println("oldObj=" + oldObj); // configs={}, age=18System.out.println("newObj=" + newObj); // configs={newK=newV}, age=18}
}

oldObj=MySerializableClass{name='zhangsan', date=Sat Nov 20 21:06:37 CST 2021, configs={}, age=18}
newObj=MySerializableClass{name='zhangsan', date=Sat Nov 20 21:06:37 CST 2021, configs={newK=newV}, age=18}


【小结】

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软Build 2016开发者大会--兑换承诺

微软的Build开发者大会已经成为它向我们宣布其在未来一年里的战略方向的一个最大平台。不像苹果的发布大会&#xff0c;微软之所以要召开这个会议并不是要发布什么产品&#xff0c;而是像众多业内人士所分析的那样&#xff0c;希望通过介绍公司的努力来说服它最重要的听众——开…

前端面试常考系列三

转载自 前端面试常考系列三 一、简述一下src与href的区别 href 表示超文本引用&#xff0c;在 link和a 等元素上使用。src 表示来源地址&#xff0c;指向外部资源所在位置&#xff0c;在 img、script、iframe 等元素上。src 的内容&#xff0c;是页面的一部分&#xff0c;是引入…

java内部类小结

【README】 1&#xff0c;本文总结了java4种内部类&#xff0c;包括 成员内部类&#xff1a;在外部类内部定义的非静态类&#xff1b;成员内部类不能独立存在&#xff0c;如 UML中类间的组合关联关系&#xff1b;静态内部类&#xff1a;在外部类内部定义的静态类&#xff1b;…

python内置模块有哪些_python中那些小众但有用的内置模块

今天带来的是python里一些小众但是却比较实用的python库&#xff0c;一起来看看吧&#xff01;pprint&#xff1a;更清晰的打印pprint 是 pretty printer 的缩写&#xff0c;用来打印 Python 数据结构&#xff0c;与 print 相比&#xff0c;它打印出来的结构更加整齐&#xff0…

微软想让你跟机器人说句话就把事办了

也别猜错&#xff0c;微软可没有像 Google 一样打算让四只脚能跑 60 迈和两只脚能穿行森林的机器人大军占领你的家。他们家的机器人不是 Robot&#xff0c;而叫 Bot&#xff0c;可能是 chatbot 的简称&#xff0c;也就是聊天机器人。 具体来说&#xff0c;微软在自然语言处理的…

转:Spring Boot 获取 HttpServletRequest 的方法

转自&#xff1a; Spring Boot 获取 HttpServletRequest 的方法 - 简书本文介绍 Spring Boot 2 获取 HttpServletRequest 的方法。 目录 概述 方法Controller 方法参数属性自动注入手动方法调用借助 Mo...https://www.jianshu.com/p/b7a7d66c4ef2 本文介绍 Spring Boot 2 获取…

前端面试常考系列四

转载自 前端面试常考系列四 一、CSS盒子模型有哪些用处 css中的盒子模型是为了理解divcss模型的定位功能&#xff0c;它利用盒子模型这样的布局方式代替了传统的表格布局方式。盒子模型是在学习divcss布局方式中必须要学习的一个模型&#xff0c;通过这个模型可以明白网页中di…

python线性加权模型_局部加权之线性回归(1) - Python实现

1 #局部加权线性回归2 #交叉验证计算泛化误差最小点345 importnumpy6 from matplotlib importpyplot as plt789 #待拟合不含噪声之目标函数10 deforiFunc(x):11 y numpy.exp(-x) * numpy.sin(10*x)12 returny13 #待拟合包含噪声之目标函数14 def traFunc(x, sigma0.03):15 y …

3分钟看完 Day2 Keynote

hey~ M姐又给大家带来了满满惊喜的 Build2016 Day 2 Keynote 干货汇总了。 如果你连昨天的都还不知道&#xff0c;那真心就 out 了。如果说信仰在昨天充值爆棚&#xff0c;今天就要充值信仰到掀翻房顶的节奏了&#xff01;&#xff01;&#xff01; 红衣主教今天妥妥变身成为新…

latex 数学公式_技能分享——LaTeX篇I

公众号文章系列二——“小袁技能分享”上线啦&#xff0c;第一篇推文我们聊一聊LaTeX(音译 “拉泰赫”)Question 1什么是LaTeX&#xff1f;要解释LaTeX是什么&#xff0c;我们先要了解另外一个事物&#xff1a;TeX。1968年&#xff0c;美国著名计算机科学家、现代计算机科学的先…

转:springboot servlet使用配置

转自&#xff1a; springboot servlet使用配置_奔跑的蜗牛的博客-CSDN博客在spring boot中添加自己的Servlet有两种方法&#xff0c;代码注册Servlet和注解自动注册&#xff08;Filter和Listener也是如此&#xff09;。 一、代码注册通过ServletRegistrationBean 获得控制。 也…

前端面试常考系列五

转载自 前端面试常考五 一、DIV元素是什么 DIV元素是用来为HTML文档内大块&#xff08;block-level&#xff09;的内容提供结构和背景的元素。DIV的起始标签和结束标签之间的所有内容都是用来构成这个块的&#xff0c;其中所包含元素的特性由DIV标签的属性来控制&#xff0c;或…

从业十余年谈谈对dotnet看法与坚持

前言 园子经常在讨论关于.Net发展的问题&#xff0c;我也这些年在工作乃至创业过程中使用.Net碰到的一些问题和看法。个人擅长的技术面&#xff0c;C/C/MFC/STL、ASM、JAVA、VB、Javascript/Typescript、C#/WebForm/MVC、Android/MonoDroid,Linux/Windows&#xff0c;还有没有可…

kali安装python3.7_Debian服务器之安装Python3.7

1、系统环境介绍1.1 系统版本debian-9.6.0-amd64-netinst1.2 系统内核Linux lnnkee 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux2、下载安装包https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz3、配置安装环境apt install libffi-dev …

org.apache.kafka.common.errors.TimeoutException: Topic not present in metadata 解决方法

【README】 本文po出了 topic not present in metadata 的解决方法&#xff1b; 很多博文说是 因为 jackson-databind 没有引入&#xff0c;但是我重新引入后&#xff0c;还是没有解决问题&#xff1b; 最后&#xff0c;原因在于我要发送消息的分区&#xff0c;topic 没有对…

前端面试常考系列六

转载自 前端面试常考系列六 一、为什么重置浏览器默认样式&#xff0c;如何重置 每种浏览器都有一套默认的样式表&#xff0c;即user agent stylesheet&#xff0c;网页在没有指定的样式时&#xff0c;按浏览器内置的样式表来渲染。这是合理的&#xff0c;像word中也有一些预留…

Microsoft将Linux带至桌面操作系统

在今天的Build大会上Microsoft宣布&#xff1a;今年的Windows 10年度更新将使得Windows 10系统能够无缝运行Linux二进制程序。多年来&#xff0c;专家与开发者都在猜测&#xff0c;Linux如何以及何时才能在普通PC用户的桌面系统中更加流行。从今天的新闻来看&#xff0c;似乎Mi…

kafka控制器,复制与存储小结

【README】 1&#xff0c;本文主要总结kafka复制&#xff0c;存储细节&#xff1b;2&#xff0c;本文的kafka集群版本是3.0.0&#xff0c; 有3个broker&#xff0c;分别是 centos201, centos202, centos203 对应的brokerid为 1&#xff0c; 2, 3 &#xff1b;【1】kafka内部原…

python开发stm32软件_ADB+Python+STM32 实现 微信跳一跳辅助

说明:安卓手机开启USB调试模式&#xff0c;具体如何开启&#xff0c;百度自己手机即可安装ADB工具安装python2.7步骤&#xff1a;1、安装adb工具下载地址&#xff1a;https://download.csdn.net/download/qq_29769263/10420731下载后解压到便于记忆的地方即可&#xff0c;以解压…

不装mono,你的.NET程序照样可以在Linux上运行

让.NET应用程序在linux上运行&#xff0c;目前通用的做法就是在Linux上安装mono&#xff0c;然后通过”mono your.exe“命令运行这个程序。 这种运行.net程序的办法有两个弱点&#xff0c;一个是需要客户机安装mono&#xff0c;二个是 ”mono xx.exe“ 这种命令行总让人感到有点…