序列化反序列化

https://www.cnblogs.com/Kidezyq/p/8025176.html

https://www.iteye.com/blog/moon-walker-2376857

https://www.iteye.com/blog/moon-walker-2376922

https://www.iteye.com/blog/moon-walker-2377021

https://www.iteye.com/blog/moon-walker-2377422

https://blog.csdn.net/lwj_zeal/article/details/90743500

https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247487597&idx=2&sn=07cb519fe78db113f63874ad0ec7452e&chksm=eb53955bdc241c4df46c7c06b1bb377d9393b084b67192a2580b968aaaa5703550767555a950&scene=21#wechat_redirect

Serializable 用来标识当前类可以被 ObjectOutputStream 序列化,以及被 ObjectInputStream 反序列化。

Serializable 接口的基本使用
通过 ObjectOutputStream 将需要序列化数据写入到流中,因为 Java IO 是一种装饰者模式,因此可以通过 ObjectOutStream 包装 FileOutStream 将数据写入到文件中或者包装 ByteArrayOutStream 将数据写入到内存中。同理,可以通过 ObjectInputStream 将数据从磁盘 FileInputStream 或者内存 ByteArrayInputStream 读取出来然后转化为指定的对象即可。

Serializable接口的特点:

1. 序列化类的属性没有实现 Serializable 那么在序列化就会报错

2. 在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供无参构造函数来重新创建对象。

如果要序列化的对象的父类 没有实现序列化接口,那么在反序列化时是会调用对应的无参构造方法的,这样做的目的是重新初始化父类的属性,例如 父类 因为没有实现序列化接口,因此对应的属性就不会被序列化,因此反序列得到的 属性值就为 null。

3. 一个实现 Serializable 接口的子类也是可以被序列化的。

4. 静态成员变量是不能被序列化

序列化是针对对象属性的,而静态成员变量是属于类的。

5. transient 标识的对象成员变量不参与序列化

6.Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片

serialVersionUID

用于确保类序列化与反序列化的兼容性问题的,如果序列化和反序列化过程中这两个值不一样,那么将导致序列化失败

序列化使用一个 hash,该 hash 是根据给定源文件中几乎所有东西 — 方法名称、字段名称、字段类型、访问修改方法等 — 计算出来的,序列化将该 hash 值与序列化流中的 hash 值相比较。

为了使 Java 运行时相信两种类型实际上是一样的,第二版和随后版本必须与第一版有相同的序列化版本 hash(存储为 private static final serialVersionUID 字段)。

serialVersionUID 发生改变有三种情况:

手动去修改导致当前的 serialVersionUID 与序列化前的不一样。

我们根本就没有手动去写这个 serialVersionUID 常量,那么 JVM 内部会根据类结构去计算得到这个 serialVersionUID 值,在类结构发生改变时(属性增加,删除或者类型修改了)这种也是会导致 serialVersionUID 发生变化。

假如类结构没有发生改变,并且没有定义 serialVersionUID ,但是反序列和序列化操作的虚拟机不一样也可能导致计算出来的 serialVersionUID 不一样。

JVM 规范强烈建议我们手动声明一个版本号,这个数字可以是随机的,只要固定不变就可以。同时最好是 private 和 final 的,尽量保证不变。
Externalizable 接口

Serializable 接口内部序列化是 JVM 自动实现的,如果想自定义序列化过程,就可以使用Externalizable接口来实现

Java 的序列化步骤与数据结构分析

序列化算法一般会按步骤做如下事情:

  • 将对象实例相关的类元数据输出。
  • 递归地输出类的超类描述直到不再有超类。
  • 类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
  • 从上至下递归输出实例的数据

 

只有实现了 Serializable 或 Externalizable 接口的类的对象才能被序列化,否则抛出异常。
对于实现了这两个接口,具体序列化和反序列化的过程又分以下3中情况:
情况1:若类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
ObjectOutputStream采用默认的序列化方式,对对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对象的非transient的实例变量进行反序列化。

情况2:若类不仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则通过反射方式进行序列化与反序列化。
ObjectOutputStream调用对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用对象的readObject(ObjectInputStream in)的方法进行反序列化。

情况3:若类实现了Externalnalizable接口,且类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
ObjectOutputStream调用对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用对象的readExternal(ObjectInput in)的方法进行反序列化。

java对象的序列化分成两部分,前一部分是对类以及成员的描述进行序列化(元数据),第二部分是对成员的值进行序列化。Java序列化框架的核心类包括:ObjectOutputStream、ObjectInputStream、ObjectStreamClass、ObjectStreamField、ObjectStreamConstants。其中序列化和反序列化的主要业务逻辑都在ObjectOutputStream、ObjectInputStream中完成,ObjectStreamClass里主要存放类描述信息,ObjectStreamField存放成员变量描述信息,ObjectStreamConstants存放的主要是一些16进制的常量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值