自定义序列化

1.问题引出

在某些情况下,我们可能不想对于一个对象的所有field进行序列化,例如我们银行信息中的设计账户信息的field,我们不需要进行序列化,或者有些field本省就没有实现Serializable接口。

java中的序列化是递归序列化,也就是你的field的引用类型中也有field可以被序列化,那么就会在序列化当前对象的时候,一同序列化

2.解决办法

使用transient(瞬变现象;过往旅客;候鸟)关键字来修饰,该关键字只能修饰属性,这样在序列化的时候,这个属性就会用默认值,例如int类型用0,引用对象用null;

但是使用transient关键字修饰的field虽然简单方便,但是会被完全隔离在序列化机制之外,这样导致在反序列化回复java对象的时候,无法取得该field的值。

因此我们可以使用自定义序列化机制,可以让程序控制如何序列化各field,甚至完全不序列化某些field(这样就与transient相同),在序列化和反序列化过程中需要特殊处理的类应该提供如下特殊签名的方法,这些特殊的方法用以实现自定义的序列化

  1. private void writeObject(java.io.ObjectOutputStream out) throws IOException;
  2. private void readObject(java.io.ObjectInputStream in)throws IOException,ClassNotFoundException;
  3. private void readObejctNoData()throws ObejctStreamException;

热爱你所写的每一行的代码

writeObject()方法负责写入特定类的实例状态,通过重写这个方法,程序员可以完全获得对序列化机制的控制,可以自主决定那些field需要序列化,需要怎么序列化,默认情况(函数体为空)该方法会调用out.defaultWriteObject来保存java对象的各field,从而达到实现序列化java对象状态的目的

readObject负责从流中读取并且回复对象的field,通过重写该方法,程序员,可以获得对反序列化机制的控制,对于反序列化各个field的顺序应该和序列化各个field的顺序相同。

至于当序列化流不完整时,readObjectNoData可以正确的初始化反序列化的对象,例如接收方接收到的序列化流残缺,或者序列化版本不同,则使用readObjectNoData来默认的初始化。

例子(对于person的改写):

  1. class Person implements Serializable
  2. {
  3. private String name;
  4. private int age;
  5. public Person(String name,int age)
  6. {
  7. this.name=name;
  8. this.age=age;
  9. }
  10. //自动生成的Get和Set方法
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. private void writeObject(ObjectOutputStream out) throws IOException
  24. {
  25. //将名字翻转之后写入二进制流
  26. out.writeObject(new StringBuffer(this.name).reverse());
  27. out.writeInt(this.age);
  28. }
  29. private void readObject(ObjectInputStream in)throws IOException,ClassNotFoundException
  30. {
  31. this.name=((StringBuffer)in.readObject()).reverse().toString();
  32. //会抛出异常,因为这里的这样写法导致同
  33. this.age=in.readInt();
  34. }
  35. }

应该提醒的是,这个自定义的功能十分强大

另外一种替换性的改写:

  1. //注意:这个方法由序列化机制调用,只要该方法存在就,它的访问控制符就可以为private protected package-private中的任意一种
  2. private Object writeReplace() throws ObjectStreamException
  3. {
  4. ArrayList<Object> list=new ArrayList<>();
  5. list.add(name);
  6. list.add(age);
  7. //我们这里返回ArrayList
  8. return list;
  9. }

序列化机制保证在序列化某个对象之前,先调用该对象的writeReplace方法,如果该方法返回另外一个java对象,系统就转换为序列化writeReplace的返回结果。(ps:如果这个返回结果也有writeReplace方法的话,就继续递归替代,直到没有替换)

相应与writeReplace相对的有一个readResolve方法,这个方法保护性的赋值整个对象,这里就不展开讨论了。

3.另外一种自定义序列化机制(介绍Externalizable)

Java还提供了另一种序列化机制,这种序列化方式完全由程序员决定存储和恢复对象数据。要实现该目标,Java类必须实现Externalizable接口,该接口里定义了如下两个方法。

  • void readExternal(ObjectInput in):需要序列化的类实现readExternal()方法来实现反序列化。该方法调用DataInput(它是ObjectInput的父接口)的方法来恢复基本类型的Field值,调用ObjectInput的readObject()方法来恢复引用类型的Field值。
  • void writeExternal(ObjectOutput out):需要序列化的类实现writeExternal()方法来保存对象的状态。该方法调用DataOutput(它是ObjectOutput的父接口)的方法来保存基本类型的Field值,调用ObjectOutput的writeObject()方法来保存引用类型的Field值。

具体的实现方式与上面自定义Serializable接口的实现类的序列化是相同的操作,这里就不阐述了,下面图是二者的比较。

java自定义序列化的更多相关文章

  1. java 自定义序列化

    pom.xml 导包 创建自己的序列化类,继承 com.fasterxml.jackson.databind.JsonSerializer<T> 抽象类 重写 serialize() 方法 ...

  2. Java 自定义序列化、反序列化

    1.如果某个成员变量是敏感信息,不希望序列化到文件/网络节点中,比如说银行密码,或者该成员变量所属的类是不可序列化的, 可以用 transient 关键字修饰此成员变量,序列化时会忽略此成员变量. c ...

  3. Java Serializable接口(序列化)理解及自定义序列化

      1 Serializable接口 (1)简单地说,就是可以将一个对象(标志对象的类型)及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等),然后可以在适当的时候再将其状态恢复(也就是反 ...

  4. Effective Java 第三版—— 87. 考虑使用自定义序列化形式

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  5. Java对象序列化剖析

    对象序列化的目的 1)希望将Java对象持久化在文件中 2)将Java对象用于网络传输 实现方式 如果希望一个类的对象可以被序列化/反序列化,那该类必须实现java.io.Serializable接口 ...

  6. 深入分析Java的序列化与反序列化

    序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...

  7. java 对象序列化 RMI

    对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数 ...

  8. Java常见序列化与反序列方法总结

    很多商业项目用到数据库.内存映射文件和普通文件来完成项目中的序列化处理的需求,但是这些方法很少会依靠于Java序列化.本文也不是用来解释序列化的,而是一起来看看面试中有关序列化的问题,这些问题你很有可 ...

  9. Java 对象序列化和反序列化

         之前的文章中我们介绍过有关字节流字符流的使用,当时我们对于将一个对象输出到流中的操作,使用DataOutputStream流将该对象中的每个属性值逐个输出到流中,读出时相反.在我们看来这种行 ...

随机推荐

  1. Java——多线程编程学习/01

    原文章:http://www.cnblogs.com/QG-whz/p/8351298.html  注:建议去看原博主的文章,单就这个知识点而论,比书本讲的透彻,如有违规,联系必删! 并发环境下进行编 ...

  2. CentOS7 Docker容器无法ping通宿主机ip问题解决记录

    Docker服务部署启动容器发现docker容器内访问宿主机IP不通,于是进入容器内ping宿主机IP,发现无法ping通,容器IP为172.17.0.2,于是继续ping172.17.0.1也不通, ...

  3. Java-对象克隆

    1. 为什么要克隆 在java中,我们通过直接=等号赋值的方法来拷贝,如果是基本数据类型是没有问题的,例如 int i = 1; int j = 0; j = i; // 直接=等号赋值,这样是没有问 ...

  4. macbook air m1上传文件到github

    一,首先安装git,打开ssh文件里的id_rsa.pub,然后复制所有内容. 二,github上申请自己的账号,右上角settings里选择SSH and GPG keys,点击new ssh ke ...

  5. 题解 「BZOJ2178」圆的面积并

    题目传送门 题目大意 给出 \(n\) 个圆,求它们并的面积大小. \(n\le 10^3\) 思路 如果您不会自适应辛普森法,请戳这里学习 其实我们发现,如果我们设 \(f(x)\) 表示 \(x= ...

  6. pycharm输入代码后,没有补全提示

    安装pycharm后,输入代码后,没有补全提示 首先检查是否关闭了代码提示,如下图,将红框中"Power Save Mode"前的勾去掉 第二步,如果在输入某些代码时还是没有补全提 ...

  7. 自定义ConditionalOnXX注解

    一.Conditional注解介绍 对SpringBoot有足够了解的小伙伴应该都用过Conditional系列注解,该注解可用在类或者方法上用于控制Bean的初始化. 常用的Conditional注 ...

  8. Java:Iterator接口与fail-fast小记

    Java:Iterator接口与fail-fast小记 对 Java 中的 Iterator接口 和 fail-fast,做一个微不足道的小小小小记 Iterator Iterator接口 Itera ...

  9. oo第三单元学习总结

    OO第三单元小结 一.JML语言理论基础及工具链梳理 在本单元我们学习了JML语言的一些基础知识,能够让我们看懂简单的JML规格并写出对应代码, 主要用到的知识点有:   1.requires 该子句 ...

  10. spring cloud config的使用

    在传统的应用中,我们的配置文件都是放在项目中,这个影响不大.但是在一个微服务架构的系统中,我们的微服务可能存在几十上百个,并且每个小的微服务可能又部署在多台机器上,那么这个时候如果我们的配置文件在都放 ...